Издательский дом ООО "Гейм Лэнд"ЖУРНАЛ ХАКЕР 130, ОКТЯБРЬ 2009 г.

Web через Zope. Обзор питоновского web-фреймворка Zope

Вадим Шпаковский (shpak.vadim@gmail.com)

В предыдущем номере журнала был сделан обзор самых популярных питоновских web-фреймворков. Продолжая тему, сегодня мы подробно рассмотрим один из них, а именно - Zope.

Zope2

В 1998 году сотруднику компании Digital Creations, Python-специалисту, Джиму Фултону было предложено прочитать лекцию по CGI (стандарт интерфейса, используемого для связи внешней программы с веб-сервером – в то время был стандартом для Питона в вебе). Согласно легенде, он ничего о CGI не знал, и его начальнику, пока они летели в самолете, пришлось рассказать ему основы CGI. С этой лекцией Фултон и выступил на конференции. Говорят, что протокол ужаснул его своей чрезмерной простотой, и он решил создать что-нибудь объектно-ориентированное. Так началась история Zope. Вскоре компания Digital Creations переименовалась в Zope Corporation и начала выпускать свой продукт под собственной Open Source лицензией ZPL.

Деньги же они зарабатывают за счет создания сайтов и консультаций. В 2000 году в ее состав вошли создатели языка Python, которых возглавлял Гвидо ван Россум (правда, сам Гвидо пробыл в Zope Corporation только до 2003 года, после чего уволился и сейчас благополучно работает в Google). Zope2 приобрел большую популярность благодаря своим особенностям. Во-первых, данные представлялись в виде объектов (что было нетипично для веба), а во-вторых, появилась возможность настраивать компоненты напрямую через браузер. Для написания простого приложения стало требоваться гораздо меньше знаний и сил. Но переход к большим серьезным проектам уже был не так-то прост. Появился даже термин «Z-образная кривая обучения», который означает, что поначалу Zope сильно облегчает жизнь, но затем требует больших усилий для понимания модели разработки. После прохождения этого этапа работать с Zope снова становится легче.

Zope3

Проект Zope3 начался в 2001 году, когда Zope Corporation экспериментировала с компонентной архитектурой. Главной целью было разбиение объектов Zope2, которые сильно разрастались в объеме, на более мелкие - компоненты. Другой целью стало сглаживание кривой обучения: Zope2 был слишком сложным, чтобы внедрить в него компонентную архитектуру. Поэтому приняли решение полностью его переписать, включив в новый проект компонентную архитектуру и все сильные стороны Zope2. Так появился Zope3, образовав две ветки продуктов Zope, которые не обладали обратной совместимостью.

Однако было уже написано слишком много кода под Zope2, чтобы забросить эту ветку. В результате, обе ветки разрабатываются параллельно (на сентябрь 2009 года последними стабильными версиями являлись 3.4.0 и 2.11.3). Нововведения в Zope3 слишком заманчивы, чтобы их игнорировать. Поэтому был запущен проект Five, который позволял использовать некоторые технологии Zope3 в Zope2. Five был интегрирован в Zope2, начиная с версии 2.8. С каждой новой версией в Zope2 становится возможным использовать все больше и больше фишек Zope3.
Далее я буду рассматривать именно Zope3.

Основные концепции

В основе многих особенностей Zope лежит его объектно-ориентированность:

  • Zope-приложение представляет собой коллекцию компонентов - объектов, с четко заданной функциональностью, которая описывается с помощью интерфейсов.
  • Каждый компонент можно заменить на любой другой с таким же интерфейсом (можно провести аналогию с моделью провайдеров в ASP.NET). Таким образом, компоненты выполняют один и тот же функционал, но разными способами. А программист выбирает из них наиболее подходящий.
  • Данные также представляются в виде объектов, которые хранятся в ZOBD (Zope Object Database).
  • Мощный механизм HTML/XML-шаблонов.
  • Широкие возможности для тестирования.
  • Многие из фишек Zope можно использовать и вне его.

Компонент контента

Zope-приложение состоит из компонентов. Один из типов компонентов - это компонент контента. Он предназначен для хранения данных. Отвечает за хранение и апдейт, но не за представление данных или их обработку. С его помощью данные отделяются от логики и представления. Но также есть возможность хранить данные прежним способом, например в реляционной базе данных. В этом случае Zope предоставляет механизм ORM, с помощью которого происходит конвертация реляционных данных в объекты и наоборот.

Адаптеры и утилиты

Адаптер - это объект, который служит своего рода «переходником» между двумя другими объектами, которые из-за разных интерфейсов не могут взаимодействовать напрямую. По-сути, адаптер превращает вызовы внешнего объекта в вызовы методов внутреннего.

Утилита отличается от адаптера тем, что не взаимодействует с другими компонентами, а просто предоставляет некоторую функциональность.

Конфиги

Все компоненты регистрируются в специальном реестре компонентов. Кроме информации о зарегистрированных компонентах, там также хранятся настройки приложения - конфиги. Для регистрации используется специальный XML-подобный язык разметки ZCML (Zope Configuration Markup Language). Файл конфигурации имеет имя и расширение configure.zcml и располагается в папке проекта. Для включения проекта в состав действующих доступных пакетов Zope необходимо дополнительно в папку etc\package-includes\ экземпляра сервера поместить файл с именем my_project_name-configure.zcml, содержащий строку <include package="my_project_name"/>.

DTML

Document Template Markup Language (DTML) - средство создания страничных шаблонов, которые поддерживают динамический контент. Он основан на тегах и скриптовом языке, и используется на стороне сервера (в отличие от JavaScript, который работает на стороне клиента).
DTML-теги поддерживают два формата: Extended Python format strings (EPFS) и HTML. Формат EPFS основан на заключении питоновских строк текста в круглые скобки для задания границ блоков кода. Дополнительный параметр форматирования позволяет указать детали преобразования данных; например: %(date fmt=DayOfWeek upper)s позволяет преобразовать дату как день недели заглавными буквами. Формат HTML использует синтаксис HTML на стороне сервера для кодирования команд вставки текстов в формируемый документ. Как и HTML-теги, тег DTML может содержать список атрибутов с присвоением значений (имя атрибута можно не указывать).

Для примера, получим информацию о текущем запросе клиента с помощью объекта REQUEST. Для этого необходимо создать страницу DTML следующего вида:

<html>
<body>
<dtml-var REQUEST html_quote>
</body>
</html>

ZPT

DTML-страницы имеют ряд недостатков, главным из которых является то, что они не предназначены для дизайнеров, работающих с HTML. Как только на HTML-странице появляется код DTML, то результат обычно становится непригодным для редакторов и браузеров. В DTML не совсем удачно разделены представление информации, логика формирования документа и контент, из которого документ формируется. Это может затруднить масштабирование содержимого и разработку самого сайта. Наконец, модель пространства имен в DTML имеет слишком много скрытых нюансов при работе с объектами и не допускает полного программного управления поиском. По прогнозам авторов Zope3, язык DTML лишен в будущем перспектив и будет удален. Подходящей альтернативой являются страничные шаблоны ZPT (Zope Page Template), при работе с которыми приходится иметь дело с языком TAL – расширением языка HTML/XML. Отличие от XML в том, что атрибут тега начинается с ключевого слова tal и отделяется от имени оператора двоеточием. Значение атрибута заключается в кавычки. Включение текста может производиться двумя способами: заменой тега и заменой содержимого тега. Замена тега на значение производится оператором tal:replace = выражение. Если необходимо включить текст внутри тега, но оставить сам тег, то используется оператор tal:content = выражение. Например, во фрагменте:

<head>
<title tal:content="template/title">
The Title
</title>
</head>

– блочный тег title будет оставлен, но его содержимое «The Title» будет заменено значением атрибута «template/title». Кроме того, существует много других полезных операторов (например, repeat, для циклов, или condition, для проверки условий).

Интерфейсы

Интерфейс в Zope выполняет такие же функции, как интерфейсы Java или C#. Интерфейс определяется как питоновский класс, наследуемый от специального класса Interface. Предположим, что нам надо создать проект книги рецептов. Вот как будет выглядеть интерфейс для получения информации о рецепте:

from zope.interface import Interface
class IRecipeInfo(Interface):
"""Give information about a recipe."""
def getName():
"""Return the name of the dish."""
def getIngredients():
"""Return a list of ingredients."""

Интерфейсы, как и классы, поддерживают наследование. Если требуется изменять содержимое рецепта, можно определить следующий интерфейс, который будет включать методы интерфейса IRecipeInfo:

class IRecipe(IRecipeInfo):
"""Give and store recipe's information."""
def setName(name):
"""Set the name of the dish."""
def setIngredients(ingredients):
"""Set the recipe's ingredients."""

Если компонент хочет реализовать определенный интерфейс, следует использовать такой синтаксис (возможна реализация нескольких интерфейсов):

from zope.interface import implements
from worldcookery.interfaces import IRecipeInfo
class RecipeInfo(object): implements(IRecipeInfo)
def __init__(self, name=u'', ingredients=[]):
self.name = name
self.ingredients = ingredients
def getName(self):
return self.name
def getIngredients(self):
return self.ingredients

В отличие от Java или C# интерфейсов, класс, который реализует Zope-интерфейс, не обязан определять все методы этого интерфейса. Ошибка возникнет только во время выполнения, когда произойдет обращение к неопределенному методу.

В модуле zope.interface есть несколько полезных методов. Например, метод alsoProvides(obj, IRecipe) подписывает объект obj (и только объект, а не класс!) на выполнение интерфейса IRecipe. Чтобы сделать то же самое для всего класса Recipe, необходимо вызвать метод classImplements(Recipe, IRecipe). Метод verifyObject(IRecipe, obj) из модуля zope.interface.verify проверяет, реализует ли объект интерфейс полностью. Метод verifyClass выполняет такую же функцию для классов.

Схемы

Описанный выше подход с определением интерфейсов с get- и set- методами не очень питоничен, особенно для простых объектов, которые просто хранят данные. Для питоновских объектов характерна работа с аттрибутами напрямую. Реализуется с помощью механизма схем следующим образом:

from zope.interface import Interface
from zope.schema import List, TextLine
class IRecipe(Interface):
name = TextLine(
title=u"Name",
description=u"Name of the dish",
required=True)
ingredients = List(title=u"Ingredients",
description=u"List of ingredients.",
required=True,
value_type=TextLine(title=u"Ingredient"))

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

Установка

  1. Установить Питон (если вдруг он все еще не стоит).
  2. Установить Zope (установщик можно скачать с официального сайта или взять на диске ][).
  3. Чтобы начать работать с Zope, необходимо создать, по крайней мере, один экземпляр Zope-сервера, который кроме сервера также содержит экземпляр базы данных (никто не мешает создать несколько таких экземпляров). Для этого нужно запустить mkzopeinstance.bat, который находится в папке <Python_dir>/Scripts, указать директорию экземпляра сервера, имя администратора и пароль. Скрипт создаст в указанной директории необходимые для функционирования сервера файлы и папки.
  4. Для запуска сервера надо запустить скрипт bin/runzope (или runzope.bat в Windows). Способ хорош при разработке приложения и не подходит для запуска готового продукта, так как он связан с терминалом. Чтобы сервер работал и при закрытии терминала, его необходимо запускать с помощью скрипта bin/zopectl с параметром start. Для остановки запусти тот же скрипт с параметром stop. Но работает только для Unix-систем (под Windows нужно провести более сложные махинации).
  5. Для создания нового проекта необходимо создать директорию <Zope_server_dir>/lib/python/<app_name>.
  6. Одна из особенностей Zope - его интерфейс управления (ZMI), который доступен после запуска сервера по адресу http://localhost:8080/manage.

Основные файлы

Zope3 устанавливается, как и все прикладные пакеты Питона, в папку <Python_dir>\Lib\site-packages, – часть инсталляционных файлов располагается в папке <Python_dir>\Scripts. В директории экземпляра сайта имеются папки bin, etc, lib. log и var.

Папка bin сайта содержит код и командные файлы для запуска системы на исполнение (в частности, runzope.bat).

Папка etc содержит конфигурационные файла сайта. Например, в файле etc/zope.conf хранятся все настройки сервера и базы данных. Секция server определяет порты протокола TCP/IP 8080 для http-сервера и 8021 для FTP-сервера. Секция zodb определяет расположение файла объектной базы данных. Секции accesslog и eventlog определяют местоположение журналов сайта для регистрации событий. Файлы principals.zcml и securitypolicy.zcml конфигурируют параметры допущенных пользователей сайта (принципалов) и их роли. Файл site.zcml – главный конфигурационный файл сайта, с ссылками на отдельные разделы, определяющие детали настроек системы.

Папка etc\package-includes содержит небольшие файлы на языке ZCML. Они определяют включение различных пакетов в текущую конфигурацию сайта. Эта папка пополняется администраторами или разработчиками новых компонент при необходимости расширить функциональность сайта.

Папка lib\python предназначена для размещения новых пакетов, определяющих особенности данного сайта. Для подключения пакета необходимо добавить ссылку на него в папку etc\package-includes.

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

Папка var содержит файлы ZODB.

Zope Management Interface (ZMI)

Среда Zope3 является одновременно сетевым сервером – публикатором хранимых на сервере в объектной базе данных экземпляров компонент и средством разработки сетевых приложений. Сетевые приложения могут разрабатываться как в режиме TTW (через сеть) с использованием вышеупомянутого ZMI, так и в режиме создания файлов проекта средствами файловой системы.

Уже упоминалось, что ZMI - это интерфейс управления, который позволяет управлять содержимым Zope. Кроме того, он дает возможность динамически управлять настройками сервера во время его работы (закладка «Сервер»). В левом верхнем углу находится навигатор - иерархическая структура объектной базы данных. В нем представлены две категории объектов – простые объекты и контейнеры. Ниже расположены другие блоки, включая меню «Добавить». Остальную часть экрана занимает рабочая область, в которой производятся различные операции над объектами.

Hello, world!

В качестве демонстрационного примера напишем страницу, которая выводит надпись «Hello, world!».

1. Создаем директорию для пакета: /lib/python/helloworld.

2. В ней создаем пустой файл __init__.py (чтобы Питон трактовал ее как пакет).

3. Тут же создай файл browser.py со следующим содержимым:

from zope.publisher.browser import BrowserView
class HelloView(BrowserView):
def __call__(self):
return """
<html>
<head>
<title>Hello World</title>
</head>
<body>
Hello, world!
</body>
</html>"""

4. Регистрируем пакет helloworld. Для этого в директории etc/package-includes создадим файл helloworld-configure.zcml, содержащий строки:

<configure
xmlns="http://namespaces.zope.org/zope">
<include package="helloworld" />
</configure>

5. Последний шаг - написание конфига configure.zcml, который нужно разместить в директории только что созданного пакета lib/python/helloworld. Этот конфиг регистрирует представление страницы с именем helloworld и открытыми правами доступа, использующей объявленный нами класс HelloView:

<configure
xmlns="http://namespaces.zope.org/browser">
<page
for="*"
name="helloworld"
permission="zope.Public"
class=".browser.HelloView"
/>
</configure>

6. Запускаем сервер и переходим по адресу http://localhost:8080/helloworld. Должна загрузиться страница с надписью «Hello, world!».

Заключение

Zope - очень солидный фреймворк, и в рамках одной статьи трудно упомянуть все его возможности, не говоря о том, чтобы рассмотреть их подробно. Хочешь подробностей? Советую посетить ресурсы, указанные на врезке. Там можно найти пару неплохих статей для начинающих. Для серьезного изучения я рекомендую книгу Суханова «Введение в Zope3». При небольшом объеме в ней рассматриваются все основные концепции. Книгу можно найти на диске ][ в разделе «Литература». Удачи!

Полезные ресурсы.

http://zope.org – официальный сайт.

http://wiki.zope.org/zope3/Zope3Wiki – если нет проблем с английским, то здесь можно найти много полезного.

http://zopelada.ru, http://zope3.ru, http://zope.net.ru – русскоязычные ресурсы.

INFO

Код Zope3 содержит более 5000 автоматических тестов, что значительно увеличивает его стабильность, особенно при внесении крупных изменений.

В 2006 году появился Grok - идейный продолжатель Zope3!

Содержание
загрузка...
Журнал Хакер #151Журнал Хакер #150Журнал Хакер #149Журнал Хакер #148Журнал Хакер #147Журнал Хакер #146Журнал Хакер #145Журнал Хакер #144Журнал Хакер #143Журнал Хакер #142Журнал Хакер #141Журнал Хакер #140Журнал Хакер #139Журнал Хакер #138Журнал Хакер #137Журнал Хакер #136Журнал Хакер #135Журнал Хакер #134Журнал Хакер #133Журнал Хакер #132Журнал Хакер #131Журнал Хакер #130Журнал Хакер #129Журнал Хакер #128Журнал Хакер #127Журнал Хакер #126Журнал Хакер #125Журнал Хакер #124Журнал Хакер #123Журнал Хакер #122Журнал Хакер #121Журнал Хакер #120Журнал Хакер #119Журнал Хакер #118Журнал Хакер #117Журнал Хакер #116Журнал Хакер #115Журнал Хакер #114Журнал Хакер #113Журнал Хакер #112Журнал Хакер #111Журнал Хакер #110Журнал Хакер #109Журнал Хакер #108Журнал Хакер #107Журнал Хакер #106Журнал Хакер #105Журнал Хакер #104Журнал Хакер #103Журнал Хакер #102Журнал Хакер #101Журнал Хакер #100Журнал Хакер #099Журнал Хакер #098Журнал Хакер #097Журнал Хакер #096Журнал Хакер #095Журнал Хакер #094Журнал Хакер #093Журнал Хакер #092Журнал Хакер #091Журнал Хакер #090Журнал Хакер #089Журнал Хакер #088Журнал Хакер #087Журнал Хакер #086Журнал Хакер #085Журнал Хакер #084Журнал Хакер #083Журнал Хакер #082Журнал Хакер #081Журнал Хакер #080Журнал Хакер #079Журнал Хакер #078Журнал Хакер #077Журнал Хакер #076Журнал Хакер #075Журнал Хакер #074Журнал Хакер #073Журнал Хакер #072Журнал Хакер #071Журнал Хакер #070Журнал Хакер #069Журнал Хакер #068Журнал Хакер #067Журнал Хакер #066Журнал Хакер #065Журнал Хакер #064Журнал Хакер #063Журнал Хакер #062Журнал Хакер #061Журнал Хакер #060Журнал Хакер #059Журнал Хакер #058Журнал Хакер #057Журнал Хакер #056Журнал Хакер #055Журнал Хакер #054Журнал Хакер #053Журнал Хакер #052Журнал Хакер #051Журнал Хакер #050Журнал Хакер #049Журнал Хакер #048Журнал Хакер #047Журнал Хакер #046Журнал Хакер #045Журнал Хакер #044Журнал Хакер #043Журнал Хакер #042Журнал Хакер #041Журнал Хакер #040Журнал Хакер #039Журнал Хакер #038Журнал Хакер #037Журнал Хакер #036Журнал Хакер #035Журнал Хакер #034Журнал Хакер #033Журнал Хакер #032Журнал Хакер #031Журнал Хакер #030Журнал Хакер #029Журнал Хакер #028Журнал Хакер #027Журнал Хакер #026Журнал Хакер #025Журнал Хакер #024Журнал Хакер #023Журнал Хакер #022Журнал Хакер #021Журнал Хакер #020Журнал Хакер #019Журнал Хакер #018Журнал Хакер #017Журнал Хакер #016Журнал Хакер #015Журнал Хакер #014Журнал Хакер #013Журнал Хакер #012Журнал Хакер #011Журнал Хакер #010Журнал Хакер #009Журнал Хакер #008Журнал Хакер #007Журнал Хакер #006Журнал Хакер #005Журнал Хакер #004Журнал Хакер #003Журнал Хакер #002Журнал Хакер #001