Различия между версиями 5 и 21 (по 16 версиям)
Версия 5 от 2010-07-05 12:27:16
Размер: 4694
Редактор: RostislavDzinko
Комментарий:
Версия 21 от 2010-07-05 14:52:02
Размер: 16335
Редактор: RostislavDzinko
Комментарий:
Удаления помечены так. Добавления помечены так.
Строка 1: Строка 1:
'''BlueBream How To''' '''!BlueBream How To'''
Строка 11: Строка 11:
Строка 18: Строка 19:
Строка 23: Строка 25:
Вы можете изменить имя вида по умолчанию для конкретного типа объектов с помощью директивы '''browser:defaultView''', доступной из ''zope.publisher''. Если имя вида по умолчанию не настроено, and when you try to access an object without specifying the view name, you will get a ComponentLookupError with a message like this: Couldn't find default view name. For example, if you try to access the root folder like: http://localhost:8080/ and name of default view is not configured, you will get an error like this: Вы можете изменить имя вида по умолчанию для конкретного типа объектов с помощью директивы '''browser:defaultView''', доступной из ''zope.publisher''. Если имя вида по умолчанию не настроено, и вы пытаетесь получить доступ к объекту не указывая имя вида, то получите ошибку !ComponentLookupError со следующим сообщением: Couldn't find default view name. Например, если вы пытаетесь получить доступ к корневой папке следующим образом: http://localhost:8080/, а имя вида по умолчанию не настроено, то ошибка будет следующей:

{{{
Строка 29: Строка 32:
Note In order to use any ZCML except few built-ins like configure and include, you include the ZCML where it is defined the directive, conventionally in BlueBream it will be inside meta.zcml for any package. For example, to use defaultView directive, you need to include meta.zcml file inside zope.publisher:
<include package="zope.publisher" file="meta.zcml" />
If you have created the application using the bluebream project template, you won’t get this error. Because there is already a a default view name (index) is configured in application.zcml configuration file inside the main package.

If there is a default view name configured, but there is no view registered with that name, you will get NotFound error when you try to access object directly without specifying the name of view. For example, if the default view name is index and there is no such view registered for root folder, you will get an error like this:
}}}

{{{#!wiki note
In order to use any ZCML except few built-ins like configure and include, you include the ZCML where it is defined the directive, conventionally in BlueBream it will be inside meta.zcml for any package. For example, to use defaultView directive, you need to include meta.zcml file inside zope.publisher:

 * <include package="zope.publisher" file="meta.zcml" />
}}}

Если вы создали приложение посредством шаблона проекта bluebream, у вас этой ошибки не возникнет, потому что в этом случае вид по умолчанию с именем '''index''' уже есть и настроен в конфигурационном файле '''application.zcml''' внутри главного пакета.

Если имя по умолчанию настроено, но вида с таким именем не существует, вы получите ошибку '''!NotFound''' при попытке получить доступ к объекту прямо без указания имени вида. Например, если вид по умолчанию - '''index''', а такой вид не зарегистрирован для корневой папки, то вы получите примерно следующую ошибку:

{{{
Строка 37: Строка 47:
As mentioned earlier, the browser:defaultView directive is defined in zope.publisher. To use this directive, you need to include meta.zcml using include directive:
}}}

Как упоминалось ранее, директива '''browser:defaultView''' определена в ''zope.publisher''. Чтобы ее использовать, нужно включить '''meta.zcml''' директивой '''include''':

{{{#!highlight xml
Строка 40: Строка 53:
For example, you can specify the default view for IContainer like this:
}}}

Например, вы можете указать вид по молчанию для '''IContainer''' следующим образом:

{{{#!highlight xml
Строка 46: Строка 62:
If index is registered as the name for default view and the view is not explicitly mentioned in the URL, BlueBream will try to get @@index view for containers. However, you need to have a browser view registered to access the view, otherwise a NotFound error will be raised as mentioned above.

More details about registering a browser view using browser:page directive is explained in Browser Page manual.
}}}

Если '''index''' зарегистрирован как имя вида по умолчанию, а вид явно не указан в URL, !BlueBream попытается получить вид '''@@index''' для контейнеров. Но вы должны иметь вид, зарегистрированный под таким именем для получения к нему доступа, в противном случае будет вызвано исключение !NotFound.

Подробнее о регистрации браузерных видов директивой '''browser:page''' рассматривается в [[http://bluebream.zope.org/doc/1.0/manual/browserpage.html#man-browser-page|документации к браузерным видам]].

= Добавление новой зависимости (пакета) =

Вы работаете в вашем экземпляре приложения или разрабатываете свой пакет, и понимаете, что он может быть полезным еще где-нибудь, скажем пакет '''ldappas'''. Отредактируйте '''setup.py''' и добавьте имя пакета в '''install_requires''':

{{{#!highlight python
setup(name='ticketcollector'
      ...
      install_requires = ['setuptools',
                          ...
                          'ldappas',
                         ],
      ...
}}}

Теперь наступает время для перестройки приложения:

{{{#!highlight bash
$ ./bin/buildout
}}}

И наконец, не забудьте зарегистрировать новый пакет в ''etc/site.zcml'':

{{{#!highlight xml
<configure xmlns="http://namespaces.zope.org/zope"
  ...
  <include package="ldappas" />
  ...
</configure>
}}}

Если в этом пакете есть новая ZCML директива, вам нужно подключить конфигурационный файл, в котором эта директива зарегистрирована. Принято регистрировать ZCML директивы в пакете ''meta''. Используйте опцию '''file''' как показано ниже:

{{{#!highlight xml
<configure xmlns="http://namespaces.zope.org/zope"
  ...
  <include package="some.package" file="meta.zcml" />
  <include package="ldappas" />
  ...
</configure>
}}}

Теперь нужно перезапустить приложение:

{{{#!highlight bash
$ ./bin/paster serve debug.ini
}}}

= Получение абсолютного URL объекта =

!BlueBream имеет другой, более ясный подход к обработке URL'ов объектов. Этот рецепт показывает, как получить URL для заданного объекта, и логику действий, которые выполняются за кулисами. Этот HOWTO предполагает, что вы подключили ''zope.traversing.browser'' в ''etc/site.zcml'' следующим образом:

{{{#!highlight xml
<include package="zope.traversing.browser" />
}}}

== Понимание механизма URL ==

Каждый персистентный объект, хранящийся в ZODB, доступен через виды, которые отвечают за его отображение. URL - это местонахождение, из которого объект доступен через браузер. Например, если пользователь пытается отобразить '''foo''', который находится в '''bar''', то наберет: http://server/foo/bar. Объект вытаскивается публикатором (publisher), который проходится по дереву объектов, начиная с корня. В нашем случае, он переходит на '''foo''', опрашивает его на предмет наличия в нем объекта '''bar''', и так дальше. '''foo''' укажет на '''bar''' публикатору, потому что его свойство '''_ _name_ _''' содержит значение '''bar'''.

Получения URL объекта производится обратным проходом от объекта к корню, с параллельным построением строки с именами всех объектов, по которым проходится публикатор.

Основная разница между более старыми версиями в том, что '''bar''' не хранит свой URL.

== Получение URL'а объекта ==

Таким образом, URL'ы всех публикуемых объектов могут быть получены, а общий класс вида AbsoluteURL обеспечивает эту возможность и существует под именем '''absolute_url'''.

Например, в ZPT, URL данного объекта можно получить так: ''my_object/@@absolute_url''. В Python коде можно использовать вызов функции ''' zope.traversing.browser.absoluteurl.absoluteURL'''.

Чтобы попробовать эту функцию, откройте отладочную оболочку:

{{{#!highlight bash
$ ./bin/paster shell debug.ini
}}}

Получить URL объекта можно следующим образом:

{{{#!highlight python
>>> from zope.publisher.browser import TestRequest
>>> from zope.traversing.browser.absoluteurl import absoluteURL
>>> request = TestRequest()
>>> absoluteURL(root, request)
'http://127.0.0.1'
}}}

В предыдущем примере '''root''' - корневая папка.

= Динамические поля в формах =

Для того, чтобы динамически добавлять поля используя механизмы ''zope.formlib'', нужно избегать наследования от '''form.EditForm'''. '''form.EditForm''' потребует также настроить адаптер для поля формы. Следующий код показывает, что нужно сделать для вставки еще одного поля в форму.

{{{#!highlight python
from zope.formlib import form
from zope.schema import TextLine

class TestForm(form.PageForm):
       my_field_name = 'something'

   def __init__(self, context, request):
       super(TestForm, self).__init__(context, request)
       self.form_fields = form.Fields(TextLine(__name__=self.my_field_name,
                                               title=u"Test Field"))

   def setUpWidgets(self, ignore_request=False):
       name = self.name
       self.widgets = form.setUpWidgets(
                         self.form_fields, self.prefix, self.context, self.request,
                         data={self.my_field_name:SOME_VALUE},
                         ignore_request=ignore_request)

   @form.action(label=_("Submit"))
   def handleSubmitAction(self, action, data):
       #do something relevant to you here
}}}

= Тестирование персистентных объектов =

Вы можете создать искусственный модуль для тестирования персистентных объектов с коммитом транзакций, в противном случае получите примерно следующую ошибку:

{{{
PicklingError: Can't pickle <class 'TestItem'>: attribute lookup __builtin__.TestItem failed
}}}

Этот HOWTO объясняет создание таких модулей для написания тестов. Функциональность для создания таких модулей обеспечивается с помощью '''zope.testing.module'''.

Внутри вашего приложения сборки заявок, создайте файл ''persistent_test.txt'' следующего формата:

{{{highlight python
:doctest:

>>> from ZODB.tests.util import DB
>>> import transaction
>>> db = DB()
>>> conn = db.open()
>>> root = conn.root()

>>> from persistent import Persistent

>>> class TestItem(Persistent):
... pass

>>> item = TestItem()
>>> root['item'] = item
>>> transaction.commit()
}}}

Теперь вызовите тест как показано ниже:

{{{#!highlight bash
$ ./bin/test
}}}

Вы должны получить следующую ошибку:

{{{
PicklingError: Can't pickle <class 'TestItem'>: attribute lookup __builtin__.TestItem failed
}}}

Теперь откройте ''tests.py'' и добавьте два ключевых аргумента в функцию '''z3c.testsetup.register_all_tests''' с именами '''setup''' и '''teardown'''. Значения этих ключевых аргументов могут быть '''zope.testing.module.setUp''' и '''zope.testing.module.tearDown''' соответственно, как показано ниже:

{{{#!highlight python
from zope.testing import module
test_suite = z3c.testsetup.register_all_tests('testp2.main', setup=module.setUp, teardown=module.tearDown)
}}}

Лучше будет создать свои собственные функции '''setUp''' и '''tearDown''', как показано ниже, так как в этом случае их, при необходимости, можно расширить. Вот функции '''setUp''' и '''tearDown''' с дополнительным кодом:

{{{#!highlight python
import z3c.testsetup
from zope.testing import module

def setUp(test):
    module.setUp(test)

def tearDown(test):
    module.tearDown(test)

test_suite = z3c.testsetup.register_all_tests('testp2.main', setup=setUp, teardown=tearDown)
}}}

По умолчанию, искусственный модуль становится '''__main__'''. Если вам необходимо другое имя модуля, можете указать его следующим образом:

{{{#!highlight python
module.setUp(test, 'mymodule')
module.tearDown(test, 'mymodule')
}}}

Теперь можно импортировать '''mymodule''' из тестов (''persistent_test.txt''). Основываясь на функциональности этого модуля, вот лучший способ создать функции '''setUp''' и '''tearDown''':

{{{#!highlight python
import z3c.testsetup
from zope.testing import module

module_name = 'testp2.main.mypersistent'

def setUp(test):
    module.setUp(test, module_name)

def tearDown(test):
    module.tearDown(test, module_name)

test_suite = z3c.testsetup.register_all_tests('testp2.main', setup=setUp, teardown=tearDown)
}}}

BlueBream How To

Виды по умолчанию для объектов

В BlueBream, вид обозревателя доступен посредством символов @@ перед его именем. Например, если у вас есть зарегистрированный вид с именем testview для контейнера с именем myobject, он доступен следующим образом: myobject/@@testview.

Контейнер

любой объект, реализующий интерфейс zope.content.interfaces.IContainer.

Вид также доступен без использования символов @@, при условии, что контент-объект с тем же именем не существует в рамках данного контейнера. В предыдущем примере, если объекта с именем testview нет в контейнере, то вид доступен через myobject/testview. Но BlueBream рекомендует всегда использовать символы @@ для доступа к видам.

Контент-объект

Если интерфейс предоставляет интерфейсный тип zope.app.content.interfaces.IContentType, то все объекты, предоставляющие этот интерфейс считаются контент-объектами.

В BlueBream index зарегистрирован как вид для интерфейса zope.container.interfaces.IContainer. Следовательно, если вы попытаетесь получить доступ к контейнеру без указания имени вида - BlueBream постарается отобразить вид зарегистрированный под именем index.

Вы можете изменить имя вида по умолчанию для конкретного типа объектов с помощью директивы browser:defaultView, доступной из zope.publisher. Если имя вида по умолчанию не настроено, и вы пытаетесь получить доступ к объекту не указывая имя вида, то получите ошибку ComponentLookupError со следующим сообщением: Couldn't find default view name. Например, если вы пытаетесь получить доступ к корневой папке следующим образом: http://localhost:8080/, а имя вида по умолчанию не настроено, то ошибка будет следующей:

ComponentLookupError: ("Couldn't find default view name",
<zope.site.folder.Folder object at 0xa3a09ac>,
<zope.publisher.browser.BrowserRequest instance
URL=http://localhost:8080>)

In order to use any ZCML except few built-ins like configure and include, you include the ZCML where it is defined the directive, conventionally in BlueBream it will be inside meta.zcml for any package. For example, to use defaultView directive, you need to include meta.zcml file inside zope.publisher:

  • <include package="zope.publisher" file="meta.zcml" />

Если вы создали приложение посредством шаблона проекта bluebream, у вас этой ошибки не возникнет, потому что в этом случае вид по умолчанию с именем index уже есть и настроен в конфигурационном файле application.zcml внутри главного пакета.

Если имя по умолчанию настроено, но вида с таким именем не существует, вы получите ошибку NotFound при попытке получить доступ к объекту прямо без указания имени вида. Например, если вид по умолчанию - index, а такой вид не зарегистрирован для корневой папки, то вы получите примерно следующую ошибку:

NotFound: Object: <zope.site.folder.Folder object at 0xac9b9ec>,
name: u'@@index'

Как упоминалось ранее, директива browser:defaultView определена в zope.publisher. Чтобы ее использовать, нужно включить meta.zcml директивой include:

   1 <include package="zope.publisher" file="meta.zcml" />

Например, вы можете указать вид по молчанию для IContainer следующим образом:

   1 <browser:defaultView
   2    name="index"
   3    for="zope.container.interfaces.IContainer"
   4    />

Если index зарегистрирован как имя вида по умолчанию, а вид явно не указан в URL, BlueBream попытается получить вид @@index для контейнеров. Но вы должны иметь вид, зарегистрированный под таким именем для получения к нему доступа, в противном случае будет вызвано исключение NotFound.

Подробнее о регистрации браузерных видов директивой browser:page рассматривается в документации к браузерным видам.

Добавление новой зависимости (пакета)

Вы работаете в вашем экземпляре приложения или разрабатываете свой пакет, и понимаете, что он может быть полезным еще где-нибудь, скажем пакет ldappas. Отредактируйте setup.py и добавьте имя пакета в install_requires:

   1 setup(name='ticketcollector'
   2       ...
   3       install_requires = ['setuptools',
   4                           ...
   5                           'ldappas',
   6                          ],
   7       ...

Теперь наступает время для перестройки приложения:

   1 $ ./bin/buildout

И наконец, не забудьте зарегистрировать новый пакет в etc/site.zcml:

   1 <configure xmlns="http://namespaces.zope.org/zope"
   2   ...
   3   <include package="ldappas" />
   4   ...
   5 </configure>

Если в этом пакете есть новая ZCML директива, вам нужно подключить конфигурационный файл, в котором эта директива зарегистрирована. Принято регистрировать ZCML директивы в пакете meta. Используйте опцию file как показано ниже:

   1 <configure xmlns="http://namespaces.zope.org/zope"
   2   ...
   3   <include package="some.package" file="meta.zcml" />
   4   <include package="ldappas" />
   5   ...
   6 </configure>

Теперь нужно перезапустить приложение:

   1 $ ./bin/paster serve debug.ini

Получение абсолютного URL объекта

BlueBream имеет другой, более ясный подход к обработке URL'ов объектов. Этот рецепт показывает, как получить URL для заданного объекта, и логику действий, которые выполняются за кулисами. Этот HOWTO предполагает, что вы подключили zope.traversing.browser в etc/site.zcml следующим образом:

   1 <include package="zope.traversing.browser" />

Понимание механизма URL

Каждый персистентный объект, хранящийся в ZODB, доступен через виды, которые отвечают за его отображение. URL - это местонахождение, из которого объект доступен через браузер. Например, если пользователь пытается отобразить foo, который находится в bar, то наберет: http://server/foo/bar. Объект вытаскивается публикатором (publisher), который проходится по дереву объектов, начиная с корня. В нашем случае, он переходит на foo, опрашивает его на предмет наличия в нем объекта bar, и так дальше. foo укажет на bar публикатору, потому что его свойство _ _name_ _ содержит значение bar.

Получения URL объекта производится обратным проходом от объекта к корню, с параллельным построением строки с именами всех объектов, по которым проходится публикатор.

Основная разница между более старыми версиями в том, что bar не хранит свой URL.

Получение URL'а объекта

Таким образом, URL'ы всех публикуемых объектов могут быть получены, а общий класс вида AbsoluteURL обеспечивает эту возможность и существует под именем absolute_url.

Например, в ZPT, URL данного объекта можно получить так: my_object/@@absolute_url. В Python коде можно использовать вызов функции zope.traversing.browser.absoluteurl.absoluteURL.

Чтобы попробовать эту функцию, откройте отладочную оболочку:

   1 $ ./bin/paster shell debug.ini

Получить URL объекта можно следующим образом:

   1 >>> from zope.publisher.browser import TestRequest
   2 >>> from zope.traversing.browser.absoluteurl import absoluteURL
   3 >>> request = TestRequest()
   4 >>> absoluteURL(root, request)
   5 'http://127.0.0.1'

В предыдущем примере root - корневая папка.

Динамические поля в формах

Для того, чтобы динамически добавлять поля используя механизмы zope.formlib, нужно избегать наследования от form.EditForm. form.EditForm потребует также настроить адаптер для поля формы. Следующий код показывает, что нужно сделать для вставки еще одного поля в форму.

   1 from zope.formlib import form
   2 from zope.schema import TextLine
   3 
   4 class TestForm(form.PageForm):
   5        my_field_name = 'something'
   6 
   7    def __init__(self, context, request):
   8        super(TestForm, self).__init__(context, request)
   9        self.form_fields = form.Fields(TextLine(__name__=self.my_field_name,
  10                                                title=u"Test Field"))
  11 
  12    def setUpWidgets(self, ignore_request=False):
  13        name = self.name
  14        self.widgets = form.setUpWidgets(
  15                          self.form_fields, self.prefix, self.context, self.request,
  16                          data={self.my_field_name:SOME_VALUE},
  17                          ignore_request=ignore_request)
  18 
  19    @form.action(label=_("Submit"))
  20    def handleSubmitAction(self, action, data):
  21        #do something relevant to you here

Тестирование персистентных объектов

Вы можете создать искусственный модуль для тестирования персистентных объектов с коммитом транзакций, в противном случае получите примерно следующую ошибку:

PicklingError: Can't pickle <class 'TestItem'>: attribute lookup __builtin__.TestItem failed

Этот HOWTO объясняет создание таких модулей для написания тестов. Функциональность для создания таких модулей обеспечивается с помощью zope.testing.module.

Внутри вашего приложения сборки заявок, создайте файл persistent_test.txt следующего формата:

{{{highlight python :doctest:

>>> from ZODB.tests.util import DB >>> import transaction >>> db = DB() >>> conn = db.open() >>> root = conn.root()

>>> from persistent import Persistent

>>> class TestItem(Persistent): ... pass

>>> item = TestItem() >>> root['item'] = item >>> transaction.commit() }}}

Теперь вызовите тест как показано ниже:

   1 $ ./bin/test

Вы должны получить следующую ошибку:

PicklingError: Can't pickle <class 'TestItem'>: attribute lookup __builtin__.TestItem failed

Теперь откройте tests.py и добавьте два ключевых аргумента в функцию z3c.testsetup.register_all_tests с именами setup и teardown. Значения этих ключевых аргументов могут быть zope.testing.module.setUp и zope.testing.module.tearDown соответственно, как показано ниже:

   1 from zope.testing import module
   2 test_suite = z3c.testsetup.register_all_tests('testp2.main', setup=module.setUp, teardown=module.tearDown)

Лучше будет создать свои собственные функции setUp и tearDown, как показано ниже, так как в этом случае их, при необходимости, можно расширить. Вот функции setUp и tearDown с дополнительным кодом:

   1 import z3c.testsetup
   2 from zope.testing import module
   3 
   4 def setUp(test):
   5     module.setUp(test)
   6 
   7 def tearDown(test):
   8     module.tearDown(test)
   9 
  10 test_suite = z3c.testsetup.register_all_tests('testp2.main', setup=setUp, teardown=tearDown)

По умолчанию, искусственный модуль становится main. Если вам необходимо другое имя модуля, можете указать его следующим образом:

   1 module.setUp(test, 'mymodule')
   2 module.tearDown(test, 'mymodule')

Теперь можно импортировать mymodule из тестов (persistent_test.txt). Основываясь на функциональности этого модуля, вот лучший способ создать функции setUp и tearDown:

   1 import z3c.testsetup
   2 from zope.testing import module
   3 
   4 module_name = 'testp2.main.mypersistent'
   5 
   6 def setUp(test):
   7     module.setUp(test, module_name)
   8 
   9 def tearDown(test):
  10     module.tearDown(test, module_name)
  11 
  12 test_suite = z3c.testsetup.register_all_tests('testp2.main', setup=setUp, teardown=tearDown)

Документации/Bluebream/BluebreamHowTo (последним исправлял пользователь RostislavDzinko 2010-07-05 14:52:02)