2. Что такое repoze.bfg
Это минималистичный web-фрэймворк, вобравший в себя идеи
Zope, Django, Pylons.
Андрей Попп: Разработка web-приложений с repoze.bfg
3. Что такое repoze.bfg
Ключевые моменты:
WSGI.
MVC (скорее даже MTV).
Компонентная архитектура.
100% покрытие тестами (по отчётам утилиты Coverage).
Отличная документация.
Андрей Попп: Разработка web-приложений с repoze.bfg
4. Что такое repoze.bfg
Фрэймворк предоставляет инструменты, помогающие решению
следующих проблем:
Конфигурация приложения.
Маршрутизация запросов.
Шаблонизация.
Аутентификация и авторизация.
Интернационализация и локализация.
Тестирование приложения.
Андрей Попп: Разработка web-приложений с repoze.bfg
5. Что такое repoze.bfg
Остальное вопросы остаются за разработчиком:
Где и как хранятся данные приложения.
Как генерировать и обрабатывать формы.
Где хранить данные сессии.
Кэширование.
Андрей Попп: Разработка web-приложений с repoze.bfg
6. Что такое repoze.bfg
Repoze.bfg использует хорошо знакомые и проверенные
технологии:
WebOb/Paste – уровень WSGI.
ZCA/ZCML – компонентная архитектура и конфигурация.
Babel – интернационализация и локализация.
Zope Page Templates – система шаблонизации.
Андрей Попп: Разработка web-приложений с repoze.bfg
8. Использование Zope библиотек
Да, repoze.bfg использует Zope библиотеки, но:
Их использование – это просто деталь реализации
фрэймворка.
Пользователь фрэймворка не обязан знать и использовать
библиотеки Zope.
Библиотеки Zope не так уж плохи.
Андрей Попп: Разработка web-приложений с repoze.bfg
9. Начинаем работать с repoze.bfg
Чтобы создать проект repoze.bfg, можно воспользоваться
одним из шаблонов Paste:
paster create -t < template_name > < project_name >
Шаблонов всего три: bfg_starter, bfg_zodb, bfg_alchemy,
bfg_routesalchemy, но об этом позже.
Андрей Попп: Разработка web-приложений с repoze.bfg
10. Начинаем работать с repoze.bfg
В результате получаем готовую структуру пакета под
управлением setuptools (или distribute).
Приложение уже настроено для запуска с помощью Paste:
paster serve paste . ini -- reload
Андрей Попп: Разработка web-приложений с repoze.bfg
11. Конфигурация приложения
Конфигурация приложения это:
URL приложения и как они отображаются на
представления.
Статические ресурсы и используемые шаблоны.
Политики аутентификации и авторизации.
Файлы с локализацией.
Компоненты, специфичные для приложения.
Почти как settings.py и urls.py в Django.
Андрей Попп: Разработка web-приложений с repoze.bfg
12. Конфигурация приложения
Конфигурацию приложения не стоит путать с настройками
приложения.
Андрей Попп: Разработка web-приложений с repoze.bfg
13. Конфигурация приложения
Конфигурация выполняется с помощью объекта Configurator:
Императивно – c помощью вызовов
Configurator.add_route, Configurator.add_view и т.д.
Декларативно – с помощью ZCML.
С помощью декораторов.
После выполнения конфигурации необходимо вызвать метод
Configurator.make_wsgi_app(), чтобы создать
сконфигурированное WSGI приложение.
Андрей Попп: Разработка web-приложений с repoze.bfg
14. Конфигурация приложения
Пример: императивная конфигурация
myproject/run.py:
...
config = Configurator ()
config . begin ()
config . add_view ( views . show_entries )
config . add_view ( views . show_comments )
config . end ()
wsgi_app = config . make_wsgi_app ()
...
Андрей Попп: Разработка web-приложений с repoze.bfg
15. Конфигурация приложения
Пример: конфигурация с помощью декораторов
myproject/run.py:
...
config = Configurator ()
config . begin ()
config . scan ()
config . end ()
wsgi_app = config . make_wsgi_app ()
...
myproject/views.py:
...
@bfg_view ()
def show_entries ( request ):
return Response ()
...
Андрей Попп: Разработка web-приложений с repoze.bfg
16. Конфигурация приложения
Пример: декларативная конфигурация с помощью ZCML
myproject/run.py:
...
config = Configurator ()
config . begin ()
config . load_zcml ( ’ configure . zcml ’)
config . end ()
wsgi_app = config . make_wsgi_app ()
...
myproject/configure.zcml:
...
< view view =" myproject . views . show_entries " >
< view view =" myproject . views . show_comments " >
...
Андрей Попп: Разработка web-приложений с repoze.bfg
17. Конфигурация приложения
Все три приведённых примера абсолютно идентичны в плане
конечного результата.
Андрей Попп: Разработка web-приложений с repoze.bfg
18. Конфигурация приложения
Но использование ZCML позволяет разрабатывать
расширяемые приложения.
Андрей Попп: Разработка web-приложений с repoze.bfg
19. Конфигурация приложения
Что такое ZCML
ZCML (Zope Configuration Markup Language) – декларативный,
основанный на XML, язык для описания конфигураций.
Для repoze.bfg cуществует набор директив ZCML (таких как
view), которые потом преобразуются в вызовы функций (в
случае с view – в вызов метода Configuration.add_view).
Андрей Попп: Разработка web-приложений с repoze.bfg
20. Конфигурация приложения
Директива ZCML – include
С помощью директивы include можно подгружать
конфигурацию из других ZCML файлов других пакетов:
...
< include package =" anotherproject " / >
< include package =" yetanotherproject " / >
...
Порядок таких включений имеет значение, потому что
директивы, встречающиеся в файлах конфигурации могут
переопределять друг друга.
Андрей Попп: Разработка web-приложений с repoze.bfg
21. Конфигурация приложения
Преобразование директив конфигурации в вызовы функций
производится только после считывания всех необходимых
файлов конфигурации.
Андрей Попп: Разработка web-приложений с repoze.bfg
22. Конфигурация приложения
Именно потому, что с ZCML возможно переопределять
конфигурацию приложения, его необходимо использовать для
разработки расширяемых приложений.
Андрей Попп: Разработка web-приложений с repoze.bfg
23. Конфигурация приложения
Пример организации ZCML конфигурации в приложении
Обычно экземпляр установленного приложения содержит
следующую ZCML конфигурацию:
...
< include package =" myproject . core " / >
< include package =" myproject . additional_module " / >
...
Андрей Попп: Разработка web-приложений с repoze.bfg
24. Конфигурация приложения
Пример организации ZCML конфигурации в приложении
Если нам нужно добавить ещё функционала в приложение:
...
< include package =" myproject . core " / >
< include package =" myproject . additional_module " / >
<include package="myproject.plugins.openid"/>
...
Мы просто подключаем конфигурацию пакета, который
предоставляет нужный функционал.
Андрей Попп: Разработка web-приложений с repoze.bfg
26. Представления в repoze.bfg
Представлением может служить, как функция вида
def my_view ( request ):
return Response ( ’ Hello , world ! ’)
так и класс с методом __call__
class MyView ( object ):
def __init__ ( self , request ):
pass
def __call__ ( self ):
return Response ( ’ Hello , world ! ’)
Андрей Попп: Разработка web-приложений с repoze.bfg
27. Представления в repoze.bfg
Аргумент request – это объект WebOb.Request.
Представление должно возвращать объект с атрибутами:
status – строка HTTP статуса.
headerlist – список HTTP заголовков.
app_iter – итератор по телу ответа.
Таким объектом, например, является WebOb.Response.
Андрей Попп: Разработка web-приложений с repoze.bfg
28. Представления в repoze.bfg
Кроме того, представление может зависеть от контекста
def my_view (context, request ):
return Response ( ’ Hello , world ! ’)
или
class MyView ( object ):
def __init__ ( self , context, request ):
pass
def __call__ ( self ):
return Response ( ’ Hello , world ! ’)
Андрей Попп: Разработка web-приложений с repoze.bfg
29. Представления в repoze.bfg
Контекст представления – это объект из предметной области
приложения.
Для каждого запроса он определяется с помощью механизма
нахождения контекста, но об этом позже.
Андрей Попп: Разработка web-приложений с repoze.bfg
30. Представления в repoze.bfg
Почему хорошо иметь в приложении контекстно-зависимые
представления:
Для разных типов контекста можно определять разные
представления.
Можно устанавливать ограничения на представления в
зависимости от контекста.
Но использование контекстно-зависимых представлений в
приложении полностью опционально, если хочется – можно
делать как в Django, Pylons. . .
Андрей Попп: Разработка web-приложений с repoze.bfg
31. Как происходит маршрутизация запросов в repoze.bfg или как
URL запроса отображается на представление?
Андрей Попп: Разработка web-приложений с repoze.bfg
32. Маршрутизация запросов
Весь процесс маршрутизации запроса происходит в две фазы:
Нахождение контекста для запроса.
Выбор представления для запроса и найденного контекста.
Андрей Попп: Разработка web-приложений с repoze.bfg
33. Маршрутизация запросов
Существует три способа организовать маршрутизацию
запросов в приложении:
Нахождение контекста с помощью обхода графа объектов
и последующий выбор представления.
Сопоставление URL запроса с шаблонами, контекст
указывается явно для шаблона URL.
Гибридный способ – сначала идёт сопоставление с нужным
URL-шаблоном, а потом обход графа объектов.
Аналогично первому способу работает Zope, второй способ
характерен для Django, Pylons и т.п.
Андрей Попп: Разработка web-приложений с repoze.bfg
34. Маршрутизация запросов
Обход графа
Удобно использовать, когда:
Множество объектов предметной области имеет структуру
графа.
URL приложения можно интерпретировать как пути в этом
графе.
Андрей Попп: Разработка web-приложений с repoze.bfg
35. Маршрутизация запросов
Обход графа
Обход графа начинается с корневого объекта.
Фабрика для создания корневого объекта указывается на этапе
конфигурации:
config = Configurator ( root_factory = some_factory , ...)
Где some_factory – это функция, которая принимает request
единственным аргументом и возвращает корневой объект.
def some_factory ( request ):
return RootObject ()
Андрей Попп: Разработка web-приложений с repoze.bfg
36. Маршрутизация запросов
Обход графа
Обычно, в качестве корневого объекта используется интерфейс
к БД или любому другому механизму хранения данных.
Андрей Попп: Разработка web-приложений с repoze.bfg
37. Маршрутизация запросов
Обход графа
Допустим, что мы проектируем приложение для управления
статическими страницами.
Кроме корневого объекта RootObject, у нас есть следующие
объекты предметной области:
Объект PageManager – это менеджер статических страниц,
через него мы можем получить нужную страницу по её
идентификатору.
Объект Page – представляет отдельную страницу.
Андрей Попп: Разработка web-приложений с repoze.bfg
38. Маршрутизация запросов
Обход графа
Как происходит обход графа на примере URL /pages/page1:
1 URL разбивается на части: [’pages’, ’page1’].
2 Вызывается метод RootObject.__getitem__ с аргументом
’pages’. Этот метод возвращает объект PageManager.
3 Вызывается метод PageManager.__getitem__ с
аргументом ’page1’. В результате получаем объект Page.
Так как частей URL у нас больше не осталось, найденный
объект Page является контекстом данного запроса.
Андрей Попп: Разработка web-приложений с repoze.bfg
39. Маршрутизация запросов
Выбор представления
После того, как мы нашли контекст, нам нужно выбрать
подходящее представление.
Андрей Попп: Разработка web-приложений с repoze.bfg
40. Маршрутизация запросов
Выбор представления
Представления для объектов предметной области
определяются на этапе конфигурации.
Императивно:
config . add_view ( show_page , for_ = Page )
config . add_view ( show_comment , for_ = Comment )
или с помощью ZCML:
< view view =" views . show_page " for =" models . Page " / >
< view view =" views . show_comment " for =" models . Comment " / >
Андрей Попп: Разработка web-приложений с repoze.bfg
41. Маршрутизация запросов
Выбор представления
Выбор представления учитывает Method Resolution Order.
Если не найдено представления для конкретного типа, будет
использовано представление для его супертипа.
Андрей Попп: Разработка web-приложений с repoze.bfg
42. Маршрутизация запросов
Выбор представления
Кроме этого, можно определять разные представления для
разных HTTP методов, разных значений HTTP заголовков и на
основе других предикатов.
Андрей Попп: Разработка web-приложений с repoze.bfg
43. Маршрутизация запросов
Шаблоны URL
Если маршрутизация запросов с помощью обхода графа не
подходит, можно использовать сопоставление URL с
шаблонами.
Андрей Попп: Разработка web-приложений с repoze.bfg
44. Маршрутизация запросов
Шаблоны URL
Механизм сопоставления URL с шаблонами работает также,
как и в Django, Routes и т.д.
Андрей Попп: Разработка web-приложений с repoze.bfg
45. Маршрутизация запросов
Шаблоны URL
Шаблоны URL приложения определяются на этапе
конфигурации.
Императивно:
config . add_route (
view = show_page ,
path ="/ pages /: page_id "
)
или с помощью ZCML:
< route
view =" views . show_page "
path ="/ p /: page_id "
/>
Андрей Попп: Разработка web-приложений с repoze.bfg
46. Маршрутизация запросов
Шаблоны URL
Контекст указывается явно:
config . add_route (
view = show_page ,
path ="/ pages /: page_id " ,
factory=" some_factory "
)
или с помощью ZCML:
< route
view =" views . show_page "
path ="/ p /: page_id "
factory=" some_factory "
/>
Андрей Попп: Разработка web-приложений с repoze.bfg
47. Маршрутизация запросов
Шаблоны URL
Для каждого шаблона можно определить несколько
представлений для разных типов контекста:
< route
name =" pages "
path ="/ p /: page_id "
factory =" some_factory "
/>
< view
route_name =" pages "
for =" Page "
/>
< view
route_name =" pages "
for =" MainPage "
/>
Андрей Попп: Разработка web-приложений с repoze.bfg
48. Маршрутизация запросов
Гибридный метод
Можно комбинировать обход графа и шаблоны URL:
< route
name =" pages "
path ="/ pages /: category_id /* traverse "
factory =" some_factory "
/>
В этом случае первая URL сначала будет сопоставляться с
/pages/:category_id, а оставшаяся часть будет
использоована для обхода графа объектов начиная с объекта,
произведённого с some_factory.
Андрей Попп: Разработка web-приложений с repoze.bfg
49. Маршрутизация запросов
Обработка исключений
Что происходит, если во время выполнения представления
происходит исключение?
Андрей Попп: Разработка web-приложений с repoze.bfg
50. Маршрутизация запросов
Обработка исключений
В этом случае контекст запроса изменяется на текущее
исключение и происходит выбор подходящего представления.
Представления для исключений регистрируются обычным
образом:
< view
for =" webob . exc . HTTPNotFound "
view =" notfound_view "
/>
Если во время исполнения любого представления произойдёт
исключение webob.exc.HTTPNotFound, то исполнение перейдёт
к notfound_view.
Андрей Попп: Разработка web-приложений с repoze.bfg
51. Шаблонизация
По-умолчанию, repoze.bfg предлагает использовать
шаблонизатор Chameleon – это реализация Zope Page
Templates и Genshi.
Кроме того, на pypi присутствует пакет repoze.bfg.jinja2 – для
работы с шаблонизатором Jinja2.
Андрей Попп: Разработка web-приложений с repoze.bfg
52. Шаблонизация
Как уже упоминалось, представление должно возращать
объект с интерфейсом Response.
Это не всегда удобно, особенно когда дело касается
тестирования, а представление рендерит тяжёлый шаблон:
response = myview ( request )
assert ’ Some text ’ in ’ ’. join ( response . app_iter )
Андрей Попп: Разработка web-приложений с repoze.bfg
53. Шаблонизация
Repoze.bfg предлагает следующее решение:
Представления возвращает dict() объект.
За преобразование этого объекта в конечный Response
ответственнен отдельный объект – рендерер.
Рендерер определяется для каждого представления на
этапе конфигурации.
Шаблоны являются рендерерами.
< view
view =" views . some_pages "
renderer =" list_pages . jinja2 "
/>
Андрей Попп: Разработка web-приложений с repoze.bfg
54. Шаблонизация
В repoze.bfg по-умолчанию присутствуют рендереры для
вывода JSON и ZPT шаблонов.
Андрей Попп: Разработка web-приложений с repoze.bfg
55. Шаблонизация
Пакет repoze.bfg.jinja2 предоставляет рендерер для шаблонов
Jinja2.
Андрей Попп: Разработка web-приложений с repoze.bfg
56. Заключение
На этом всё. Читайте документацию –
http://docs.repoze.org/bfg/.
Андрей Попп: Разработка web-приложений с repoze.bfg