среда, 23 апреля 2008 г.

z3c tutorial, часть третья

3 Создание форм при помощи z3c.form

По логике, следующим шагом для ZContact была бы возможность добавлять контакты, через форму, которая спрашивала бы у нас имя и фамилию нового контакта. Мы можем генерировать такую форму с помощью schema (IContact), определенную нами в interfaces.py с использованием пакета z3c.form

3.1 Добавление z3c.form и z3c.formui в качестве зависимостей

Однако, прежде чем мы сможем использовать z3c.form, мы должны добавить ее в качестве зависимости к нашему приложению.

Чтобы добавить z3c.form как зависимость, откройте setup.py в корневой директории вашего приложения и добавьте 'z3.form' параметру install_requires (где-то возле 25 линии :). В это время вам следует также добавить z3c.formui и z3c.layer в качестве зависимостей, которые необходимы для отрисовки в клевой верстке.

Следующее, что вы захотите, это включить zcml-конфигурацию для z3c.form и z3c.formui в файл configure.zcml, расположенный в zcontact/src/configure.zcml. z3c.form makes use (делает применение?) другие многочисленные компоненты z3c.*, которые определяют новые zcml-директивы.

Для использования этих директив вы должны включить метафайлы в начало файла сonfigure.zcml перед всеми другими инклюдами (include).


Следующее, что вам нужно, это включить реально (?) пакеты z3c.form и z3c.formui в конец конфигурационного файла configure.zcml.


Теперь все, что мы должны сделать, это перезапустить процесс сборки, чтобы загрузились и стали доступны новые яйца-капсулы для z3c.form и z3c.formui.

$ ./bin/buildout -N
Опция -N указана для того, чтобы не загружались уже скачанные яйца (настоятельно рекомендуется).

3.2 Настройка вашего приложения для работы с z3c.form

К сожалению, мы еще не совсем готовы к использованию z3c.form. Из-за того, что пакеты z3c созданы с неким другим шаблоном для создания приложений, необходимы ее кое-какие шаги, чтобы заставить их работать. Одним из таких шагов будет установка своего собственного слоя и скина. К несчастью, многие zcml-директивы не помогут вам объяснить, для какого слоя вам необходимо зарегистрировать страницу или вид. Если вы не укажете слой, он регистрируется со слоем по-умолчанию. Это отключит все те пакеты, которые зарегистрировали все свои собственные виды со слоем по-умолчанию, делая этот слой сильно загрязненным всяким ненужным нам барахлом. Избежать этого непотребства, пакеты z3c.* регистрируют все свои виды по запросу на слое, специфичному (?) пакету. Чтобы правильно использовать z3c.* пакет, вы должны расширить эти слои со своим собственным. Сейчас мы создадим слой, который позволит нам использовать виды из пакета z3c.form.

3.2.1 Создание слоя

Создайте новый файл src/zcontact/layer.py и добавьте в него следующий код:

1
2
3
4
5
from z3c.form.interfaces import IFormLayer
from z3c.layer.pagelet import IPageletBrowserLayer

class IZContactBrowserLayer(IFormLayer, IPageletBrowserLayer):
"""ZContact browser layer with form support."""

IFormLayer имеет виды для всех виджетов, используемых в генерируемых формах, а IPageletBrowserLayer предоставляет различные полезные виды утилит, таких как error.

3.2.2 Создание скина

Чтобы получить доступ к этому слою из браузера, мы должны создать скин. Итак, создадим еще один файл src/zcontact/skin.py и добавьте туда следующий код:

1
2
3
4
5
6
7
import z3c.formui.interfaces

from zcontact import layer

class IZContactBrowserSkin(z3c.formui.interfaces.IDivFormLayer,
layer.IZContactBrowserLayer):
"""The ZContact browser skin using the div-based layout."""

Заметьте, что наш скин наследуется от IDivFormLayer, определенный в пакете z3c.formui. Когда форма отрендерится, поля возникнут в тегах, а не в таблице. Существует еще слой для верстки, основанной на таблицах. Благодаря компонентной архитектуре, также возможно написать свой собственный слой верстки форм, но мы не будем здесь этого делать. :)
Сейчас мы должны зарегистрировать скин в zcml с новым файлом src/zcontact/skin.zcml. Мы сделаем доступным наш скин через http://localhost:8080/++skin++ZContact/. В файле будет следующее:


Не забудьте включить этот новый zcml-файл в zcontact/configure.zcml линией package="zcontact" file="skin.zcml" />.

3.3 Создание формы добавления

Мы начнем создание нового модуля zcontact.browser, добавив директорию browser в src/zcontact с пустым файлом __init__.py. Теперь мы можем создать и открыть новый файл zcontact/browser/contact.py, где мы определим все формы.
Начнем с добавления следующего кода в файл browser/contact.py:

1
2
3
4
5
6
7
8
9
from z3c.form import form, field

from zcontact import interfaces


class ContactAddForm(form.AddForm):
"""A simple add form for contacts."""

fields = field.Fields(interfaces.IContact)
Класс form.AddForm, от которого мы сейчас унаследовались, определяет для создания и добавления наших новых объектов несколько методов, которые мы переопределим позднее и на форме добавления можно найти несколько кнопок.
Затем мы добавим страницу, которая использует этот класс для отображения ормы. Откройте zcontact/browser/configure.zcml и добавьте следующее:

 1
2
3
4
5
6
7
8
9
10
11
 xmlns="http://namespaces.zope.org/browser">


name="addContact.html"
for="zope.app.folder.interfaces.IFolder"
permission="zope.Public"
layer="zcontact.layer.IZContactBrowserLayer"
class=".contact.ContactAddForm"
/>

Мы зарегистрировали страницу под именем addContact.html для интерфейса IFolder. Поскольку корневая папка каждого нового экземпляра zope реализует IFolder, мы должны иметь возможность (сможем) получить доступ к этой странице по адресу http://localhost:8080/++skin++ZContact/@@addContact.html. Не забудьте включить пакет browser в файл zcontact/configure.zcml, добавив в самый конец строчку package=".browser" />.
Теперь мы готовы к действию, итак, перезапустим сервер с помощью команды ./bin/paster serve deploy.ini (или debug.ini, если пожелаете) и зайдем по адресу http://localhost:8080/++skin++ZContact/@@addContact.html. Вы должны увидеть очень простую форму по типу:



3.4 Доводим до конца форму добавления

Если вы действительно попробовалииспользовать форму добавления и нажимали на кнопку, вы должны были получить ошибку NotImplemented. Если вы выбирали запуск paster с конфигурацией debug.ini, а не deploy.ini, вероятно вы получали клевый (прикольный) экран по типу следующего:



Из этово экрана вы можете раскрыть любую строчку в трассировке и вставить туда код python, чтобы отладить проблему. Я был очень удивлен (и я тоже, - прим. переводчика), когда впервые увидел это.
Чтобы исправить ошибку, мы должны реализовать три метода для класса ContactAddForm: create, add и nextURL. Я решил реализовать то по-быстрому, как показано ниже, хотя, конечно, никто не мешает вам сделать это по-своему.

 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
from z3c.form import form, field

from zcontact import interfaces
from zcontact.contact import Contact


class ContactAddForm(form.AddForm):
"""A simple add form for contacts."""

fields = field.Fields(interfaces.IContact)

def create(self, data):
contact = Contact()
form.applyChanges(self, contact, data)
return contact

def add(self, contact):
self._name = "%s-%s" % (contact.lastName.lower(), contact.firstName.lower())
self.context[self._name] = contact

def nextURL(self):
return '/'

В методе create мы использовали функцию form.applyChanges для установки значений атрибутов нового контакта firstName и lastName. Данные, передаваемые методу create соотносятся между именами полей и введенными данными, уже приведенными к правильным типам python. Например, мы должны получить contact.firstName = data['firstName']. Я жестко установил методу nextURL возвращать путь, который отправлял бы нас назад к скину по-умолчанию Rotterdam, где вы сможете увидеть заново созданный контакт в виде содержимого. Мы сделали это, так как еще не написали свой собственные контентные виды для нашего слоя/скина и должны возвращаться в Rotterdam.

3.5 Формы отображения и редактирования

Формы отображения и редактирования еще проще, чем формы добавления, тк как вам не нужно реализовывать дополнительные методы. Давайте начнем с создания такой формы отображения.

3.5.1 Создание формы отображения

Для создания формы отображения нам понадобится новый класс, который бы наследовался от form.Form. Чтобы виджет отображался как обычный текст, а не форма ввода, мы должны установить для формы режим DISPLAY_MODE, это обычная константа, которую нужно импортировать из z3c.form.interfaces, (добавив строку импорта from z3c.form.interfaces import DISPLAY_MODE - прим. переводчика). Откройте файл zcontact/browser/contact.py и добавьте следующий код:

1
2
3
4
5
class ContactDisplayForm(form.Form):
"""A simple display form for contacts."""

fields = field.Fields(interfaces.IContact)
mode = DISPLAY_MODE

и не забудьте зарегистрировать новую форму в configure.zcml (не который корневой, а который в папке browser - прим. переводчика) с помощью следующего:

1
2
3
4
5
6
7

name="index.html"
for="..interfaces.IContact"
permission="zope.Public"
layer="zcontact.layer.IZContactBrowserLayer"
class=".contact.ContactDisplayForm"
/>

Сейчас, когда у нас есть форма отображения, мы можем изменить nextURL класса ContactAddForm, чтобы он указывал на вновь созданный контакт. Теперь он будет выглядеть следующим образом:

1
2
def nextURL(self):
return absoluteURL(self.context[self._name], self.request)


Не забудьте включить линию from zope.traversing.browser.absoluteurl import absoluteURL в начало файла! Если все получилось, вы можете рестартовать сервер и добавить новый контакт по адресу http://localhost:8080/++skin++ZContact/@@addContact.html, чтобы открыть форму отображения. Она будет выглядеть примерно так:





3.5.2 Добавление кнопок в форму

А теперь давайте-ка добавим две кнопочки, одну для редактирования, другую для удаления контакта. Начнем с добавления строчки from z3c.form import button в начало файла contact.py.

Когда пользователь нажимает кнопку, данные формы отправляются по адресу url, указанному в атрибуте action формы. По-умолчанию, action установлено в url самой формы, так что, когда нажимаем кнопку, порма просто перезагружается. Когда форма отрабатывается, проверяется, какая кнопка была нажата и вызываются соответствующие обработчики (handlers), которые определены как методы в классе ContactDisplayForm. Кроме того, при помощи z3c.form мы можем определить кнопку и обработчик, используя декоратор. Для кнопки удаления мы заходим удалить контакт и отправить пользователя назад на форму добавления. Добавим следующий код в класс ContactDisplayForm:

1
2
3
4
5
6
7
@button.buttonAndHandler(u'Delete', name='delete')
def handleDelete(self, action):
name = getName(self.context)
parent = getParent(self.context)
del parent[name]
nextURL = absoluteURL(parent, self.request)+'/@@addContact.html'
self.request.response.redirect(nextURL)

Убедитесь, что вы добавили следующие строчки импорта в начало файла:

1
2
3
4
from z3c.form import form, field, button
from z3c.form.interfaces import DISPLAY_MODE
from zope.traversing.browser.absoluteurl import absoluteURL
from zope.traversing.api import getParent, getName
(А у меня еще была строчка from zcontact.contact import Contact, может она не нужна?

Действительно, если ее упустить, то в дебаг-мод можно увидеть трейссинг следующего вида:


А еще конечно же не забываем про from zcontact import interfaces. Таким образом, у нас будет наверху следующий импорт:

from zope.traversing.browser.absoluteurl import absoluteURL
from z3c.form import form, field, button
from z3c.form.interfaces import DISPLAY_MODE
from zcontact import interfaces
from zcontact.contact import Contact
from zope.traversing.api import getParent, getName

Так что смотрим внимательно за тем, что делаем! - прим. переводчика)

Теперь добавим кнопку редактирования. У нас еще нет пока формы редактирования, так что кнопка редактирования будет вести нас на несуществующую страницу. Пока просто забьем место этим. Добавьте следующее в класс ContactDisplayForm:

1
2
3
4
@button.buttonAndHandler(u'Edit', name="edit")
def handleEdit(self, action):
nextURL = absoluteURL(self.context, self.request) + '/@@editContact.html'
self.request.response.redirect(nextURL)

Теперь вы можете рестартовать сервер и попробовать кнопки (Зайдите по адресу http://localhost:8080/++skin++ZContact/@@addContact.html, добавьте контакт и полюбуйтесь - прим. переводчика). Ваша форма будет похожа на следующую:




3.5.3 Создание форм для редактирования

К этому времени вы должны быть близки к уровню профи в деле автогенерируемых форм. Нашим финальным аккордом будет создание формы редактирования, которая самая простенькая из всех. Вот код, который вам нужно добавить:

1
2
3
4
class ContactEditForm(form.EditForm):
"""A simple edit form for contacts."""

fields = field.Fields(interfaces.IContact)
и всего-то еще необходимую zcml-конфигурацию:

1
2
3
4
5
6
7

name="editContact.html"
for="..interfaces.IContact"
permission="zope.Public"
layer="zcontact.layer.IZContactBrowserLayer"
class=".contact.ContactEditForm"
/>
Теперь возьмем и попробуем нашу форму для редактирования, нажав кнопку Edit с формы отображения (то есть сначала, конечно, нужно зайти по адресу http://localhost:8080/++skin++ZContact/@@addContact.html и добавить контакт, а потом с формы отображения нажать на Edit - прим. переводчика). Вы можете заметить, что мы уже имеем кнопку Apply для внесения изменений. После редактирования вам представят статусное сообщение об успехе или провале. С этого момента, мы вернемся к форме добавления и добавим кнопку 'Done' в класс ContactEditForm с помощью кода:

1
2
3
@button.buttonAndHandler(u'Done', name='done')
def handleDone(self, action):
self.request.response.redirect(absoluteURL(self.context, self.request))
Но постойте! Как только мы создали свою собственную кнопку, мы переопределили кнопки, декларируемые в классе form.EditForm. Чтобы избежать этого, мы должны расширить (extend) класс form.EditForm, поместив form.extends (form.EditForm) после декларации класса ContactEditForm. Теперь вы должны иметь форму для редактирования по типу следующей:




3.6 Завершение приложения заглавной страницей

Прежде чем мы ринемся в скиннинг, давайте сделаем еще одну страницу для целостности нашего приложения. Следующая страница будет заглавной страницей нашего приложения и будет предоставлять ссылку на форму добавления и ссылки на каждый существующий контакт. Это все можно сделать в простом шаблоне в zcontact/browser/frontpage.pt


Чтобы это появилось в главной странице нашего приложения, нам нужно зарегистрировать страницу в zcml для интерфейса IRootFolder. Добавим следующее в файл zcontact/browser/configure.zcml:


Перезагрузите ваш сервер и проверьте http://localhost:8080/++skin++ZContact/ и вы должны увидеть что-то похожее.



Итак, с несколькими готовыми формами и сносно работающим приложеньицем, мы можем начать изучение других пакетов z3c.*.

среда, 16 апреля 2008 г.

z3c-tutorial. 2 глава!

Это вторая глава переводимой мной документации z3c-tutorial, оригинал которой доступен по адресу http://docs.carduner.net/z3c-tutorial. Итак, поехали!

2 Приступая к работе


2.1 Установка виртуального окружения

Прежде чем мы начнем работать над нашим приложением, хорошей идей будет настроить окружение питона, которое отделено от системного питона, предустановлого с каким-то используемым вами дистрибутивом linux (в моем случае это Ubuntu Gutsy) (А в моем это OpenSUSE 10.3 - прим. перев. :). Создав "виртуальную" среду питона, мы сможем избежать множества различных проблем, связанных с системным питоном, таких как: неработающие пакеты, конфликтующие зависимости и т.д.).

Виртуальную среду питона можно легко создать с помощью скрипта virtualenv.py, доступного по адресу: http://svn.colorstudy.com/virtualenv/trunk/virtualenv.py. Подробнее о том, что делает этот скрипт, можно почитать на странице pypi: http://pypi.python.org/pypi/virtualenv.
Загрузите этот скрипт в вашу домашнюю директорию и создайте новое окружение с именем sandbox:
$ wget http://svn.colorstudy.com/virtualenv/trunk/virtualenv.py ~/
$ python ~/virtualenv.py sandbox

В качестве альтернативы вы можете поместить эту среду в любое место, куда вам захочется, и назвать так, как вам нравится! Эта папка сейчас имеет директорию bin с новым исполняемым файлом python и скриптом easy_install. Еще там лежит bash-скрипт для помещения вашей оболочки в новую среду, так что вы не должны набирать полный путь для запуска питона из нашего окружения. Давайте-ка запустим это:

$ cd sandbox
$ source bin/activate

После этого мы можем убедиться в том, что это все работает:

(sandbox)$ which python
/home/pcardune/sandbox/bin/python

Начиная с этого момента, везде, где вы увидите запущенную shell-команду, подразумевается, что вы запустили виртуальное окружение.

2.2 Использование zopeproject

Было бы неплохо начать работу с простейшего каркаса приложения, так чтобы не нужно было беспокоиться о написании всей конфигурации с нуля. К счастью, для этого Philipp von Weitershausen уже написал замечательное средстов, названное zopeproject

zopeproject можно установить с помощью скрипта easy_install. Для этого просто наберите:

$ easy_install zopeproject

Теперь создадим новый проект под названием zcontact. zopeproject создаст всю основную конфигурацию, которая вам понадобится для того, чтобы запустить пустое zope-приложение и войти под аккаунтом администратора. Вас попросят ввести имя и пароль к административному аккаунту (который можно будет изменить в любое время), а также расположение для установки необходимых компонентов.

$ zopeproject zcontact
Enter user (Name of an initial administrator user): manager
Enter passwd (Password for the initial administrator user): zcontact
Enter eggs_dir (Location where zc.buildout will look for and place packages) ['/home/pcardune/buildout-eggs']: eggs

Этот шаг может занять несколько

минут, так как будет загружаться много кода и некоторый из них будет откомпилирован. Пока вы ждете, я настоятельно рекомендую поглядеть документацию по zopeproject, чтобы лучше понять, чего он там делает.

2.3 Запуск сервера

Когда все будет завершено вы можете зайти прямо туда (а можно попрыгать сначала и поплясать драмак - прим. перев. :) и запустить ваше зарождающееся приложение, которое по умолчанию запустится на 8080 порту:

$ cd zcontact
$ ./bin/paster serve deploy.ini

Starting server in PID 23818.
serving on http://127.0.0.1:8080

Сейчас вы должны получить пустой zope-экран, который выглядит примерно так:

images/screen1.png

Файл deploy.ini, передаваемый команде ./bin/paster, указывает опции для запускаемого сервера, например, такие как настройки порта. zopeproject также генерирует файл debug.ini, который включает WSGI-фильтр для управления ошибками. Даже когда вы запустились с ошибками, вы можете использовать конфигурацию debug.ini для отслеживания кода, как он запускается, прямо в вашем браузере!

2.4 Регулировка настроек безопасности

Чтобы упростить себе работу в этом руководстве, мы настроим права, генерируемые zopeproject'ом, так, чтобы нам не пришлось заботиться о них в дальнейшем. Добавим следующие строчки в файл site.zcml, который находится в корневой директории вашего приложения:





Это даст полный доступ ко всему без ограничений анонимным пользователям.

2.5 Создание простого интерфейса и реализации

Перед тем как окунуться в мир пакетов z3c.*, мы должны иметь некий объект, с которым мы будем играться. Поскольку ZContact'у полагается быть менеджером контактов, давайте начнем с объекта контакт. Чтобы он был попроще, у нас будет всего два поля: имя и фамилия (first name и last name).

Примечание

Весь исходный код располагается в папке zcontact/src/zcontact, так что zcontact/src/zcontact/interfaces.py можно импортировать как import zcontact.interfaces.

2.5.1. Интерфейс IContact

Откройте файл interfaces.py и добавьте следующее:
1
2
3
4
5
6
7
8
9
10
11
12
13
import zope.interface
import zope.schema

class IContact(zope.interface.Interface):
"""A simple contact."""

firstName = zope.schema.TextLine(
title=u"First Name",
required=True)

lastName = zope.schema.TextLine(
title=u"Last Name",
required=True)
2.5.2 Реализация Contact

Теперь по-быстренькому мы можем сделать нашу реализацию. Откройте contact.py и добавьте следующее:
1
2
3
4
5
6
7
8
9
10
11
import zope.interface
from zope.schema.fieldproperty import FieldProperty

import interfaces

class Contact(object):
"""See ``zcontact.interfaces.IContact``."""
zope.interface.implements(interfaces.IContact)

firstName = FieldProperty(interfaces.IContact['firstName'])
lastName = FieldProperty(interfaces.IContact['lastName'])
2.5.3 Регистрация безопасности для класса Contact

Еще нам нужно зарегистрировать класс Contact в zcml и настроить права для доступа к атрибутам. Просто добивим следующее в файл src/zcontact/configure.zcml

Когда все это проделано, мы можем окунуться в виды, которые используют компоненты z3c.*!

Внимание!

Не забудьте, в реальном мире вам сначала следовало бы написать unit-тесты для этого кода, чтобы убедиться в том, что класс Contact действительно реализует интерфейс IContact!

вторник, 15 апреля 2008 г.

Перевод z3c-tutorial

Оригинал доступен по адресу http://docs.carduner.net/z3c-tutorial/. Сразу скажу, что пишу этот перевод в первую очередь для себя. Дополнения, замечания приветствуются. Итак, поехали!

1 Введение

За прошедшие девять или около того месяцев с того момента как Philipp von Weitershausen опубликовал второе издание книги "Разработка Веб-компонентов с помощью Zope 3 (Web Component Development with Zope 3)", Zope 3 претерпела значительные изменения и реструктуризацию. Приложение, некогда известное как Zope 3, разбилось на сотни частей, которые все вместе составляют "среду разработки Zope 3" ("Zope 3 the framework"). Каждый Zope-компонент стал отдельным пакетом, разделяемым посредством капсул-яиц (eggs), со сложной древовидной структорой (ever-complex dependency trees). Еще одно важное изменение для Zope за прошедшие 9 месяцев было создание множества пакетов, поддерживаемых сообществом, которые не входят в ядро Zope. Это z3c.* пакеты. Написанные преимущественно преданными и упорными Zope 3-хакерами, старающимися сделать Zope еще мощнее, чем раньше, пакеты z3c.* быстро стали центром внимания. К несчастью, нам, простым смертным (Unfortunately for the rest of us :), те, кто знал, как использовать пакеты z3c.*, были слишком заняты своей работой, будучи невероятно продуктивными и успешными, никогда не писали никаких новых книг, руководств или изи-ту-фоллоу (легкой в освоении - прочитал и сделал) документации. Этот документ нацелен на облегчение жизни тем, кто все еще делает вещи по-старому, и предоставляет легкое и непринужденное введение в z3c.*.


1.1 Для кого предназначено (и не предназначено) данное руководство


Это руководство было изначально написано для тех, кто уже имел некоторый опыт работы с Zope 3. Предполагается, что читатель имеет определенный уровень понимания касательно основных парадигм Zope, а именно: компонентной архитектуры, конфигурации ZCML, tal страниц шаблонов (tal page templates) и, конечно же, питона. К счастью, существуют отличные книги, в которых раскрываются данные темы. Если вы еще не читали, я настоятельно рекомендую вам обратить внимание на книгу "Разработка Веб-компонентов с помощью Zope 3 (Web Component Development with Zope 3)", автор Philipp von Weitershausen, и использовать ее в качестве дополнения к этому руководству. Baiju M также написал великолепную онлайн-книгу, описывающую все детали компонентной архитектуры. Эту книгу вы можете найти по адресу: http://www.muthukadan.net/docs/zca.html