Contents
Zopeは、それをモノにしたときのすばらしい悟り体験のために勉強しましょう
—How To Become A Pythonista
嘘です。
まあでも、Zopeを実戦で使うことはなかろうとも、そのコンセプトを知るのは無駄ではないでしょう。 特にPyramidはrepozeというZopeとWSGIの合流を目的にしたプロジェクトが出自なので、Zopeからのアイディアも多く採用されています。 Pyramidを使っていてZopeを再発見することも少なからずあるようなので、今更ながらでもZope2で遊ぶガイドとして、なんか書いてみようと思います。
Zopeとは?
Zopeの言葉がさまざまに利用されているため、どれがZopeなのかわかりにくくなっています。 だいたい以下のものがZopeな気がします。
- Zope2
- Zope Corporation
- 過去にZope3と呼ばれていたBluebreamというフレームワーク
ここではZope2だけを対象にします。
Zope3はコンポーネントに分解され、汎用コンポーネントはZope Toolkitに、管理画面などのアプリケーション部分は Bluebreamになりました。 Zope Toolkitは Bluebreamも使っていますが、Zope2やgrok, Ploneなどが使うようになっています。
Zope2はフレームワークではなく、アプリケーションサーバーです。 開発者はZope2上にアプリケーションとなるクラスやオブジェクトを登録して、WebアプリケーションをZope2アプリケーションサーバー上で実行させることになります。
buildout
Zope2に限らずZope Toolkitを使うプロジェクトは多くの場合 zc.buildout を使って開発環境を構築します。
zc.buildoutは、環境構築の手順をパッケージにしたrecipeを使って環境構築を行います。 Zope2の環境構築には、 plone.recipe.zope2instance がよく用いられます。
buildoutによる環境構築は以下のような手順になります。
# bootstrap.py を実行してbuildoutを使えるようにする # buildout.cfg でレシピなどの設定をする # bin/buildout でbuildout.cfgで設定された内容を実行する
Zope2の環境を構築する
buildout.cfgを書く
まずは環境構築のためにbuildout.cfgを書きましょう。
buildout.cfg:
[buildout] extends = http://download.zope.org/Zope2/index/2.13.21/versions.cfg parts = zope2 instance interpreter = zopepy [zope2] recipe = zc.recipe.egg eggs = Zope2 [instance] recipe = plone.recipe.zope2instance eggs = ${zope2:eggs} user = admin:admin http-address = 8080
buildoutでは、このファイルの各セクション(buildout, zope2, instanceなど)をpartといいます。 buildoutパートでは、extends, partsを指定しています。 buiildoutの設定ファイルは継承可能なので、extendsで他の設定ファイルを指定すると、その設定を受け継ぐようになります。 この例では Zope2 2.13.21で利用するライブラリバージョンなどが受け継がれます。 (気になる人は実際に http://download.zope.org/Zope2/index/2.13.21/versions.cfg をダウンロードして中を見てみましょう)
zope2パートでは必要なライブラリを設定しています。 zc.recipe.eggは、ライブラリをまとめて、それらのライブラリをPYTHONPATHに含めるなど、virtualenvとpipを合わせたような環境作成を行います。 interpreterで指定したzopeppyという名前のコマンドが作成されます。 そのコマンドを実行すると、eggsで指定したライブラリが利用可能なpythonインタプリタが起動されます。 ひとまずZope2を動かすだけなので、必要なのはZope2です。
instanceパートではZope2の実行環境構築の設定をしています。 eggsでは、 zope2パートのeggsと同じ内容とするため、 ${zope2:eggs} というプレースホルダーを使っています。 他にもオプションの設定がありますが、とりあえずZope2アプリケーションサーバーを立ち上げるにはこれで十分です。
bootstrapして、buildoutして..
buildoutするには、zc.buildoutをインストールしますが、site_packagesなどにはインストールせずに、プロジェクト直下にインストールします。 そのためのスクリプトが bootstrap.py です。 http://downloads.buildout.org/1/bootstrap.py からダウンロードしてきましょう。 bootstrap.pyを先ほど作成したbuildout.cfgと同じディレクトリにコピーします。 また、既存のPython環境から隔離するため、virtualenvを使います。
以下のように、実行します。
$ virtualenv env $ env/bin/python bootstrap.py $ bin/buildout
Zope2を立ち上げる
buildoutでZope2の環境ができあがりました。 plone.recipe.zope2instance で instance コマンドが作成されています。 instance fg でフォアグランド実行ができます。 ひとまずこれで立ち上げて動作を確認してみましょう。
$ bin/instance fg
http://localhost:8080 でZope2が実行されているのがわかります。 management interface(ZMI) にはbuildoutで設定した admin ユーザーでログインできます。
ZMIの使い方はここでは説明しませんが、 Zope2 Book などが参考になるでしょう。
Zope2プロダクト開発
Zope2上のアプリケーションは過去に Products フォルダに入れなければなりませんでした。 現在ではそのような制限はなくなりましたが、互換性のためにProducts名前空間を使っているZope2アプリケーションも多くあり、総じてZope2アプリケーションはプロダクトと呼ばれます。
Zope3スタイルとfive.grok
Zope2はすでにZope Toolkitを使っているので、その中で動かすアプリケーションでも利用できます。 便宜上Zope3スタイルと呼んでおきます。
Zope2の伝統的なアプリケーションでは、オブジェクトが直接ビューを返すメソッドを持っています。 Zope3スタイルではこれを分離して扱います。
Zope3スタイルでそのまま実装しようとすると、configure.zcmlに多くのコンポーネント設定を書くことになります。 GrokというZope3フレームワークがあり、これは、configure.zcmlに書くことなく、規約でコンポーネントを構成しています。 この技術をさらにZope2上で利用できるようにしたものがfive.grokです。 (Zope3の技術をZope2にバックポートするものは Five という名前空間を使うのが慣例です。)
プロジェクトの作成
Zope2プロダクトと言えども、Pythonパッケージであることは変わりません。 ただし、プロダクトごとに細かくパッケージを分けたりするので、 mr.developer で管理してみましょう。 mr.developerを使うと、開発中パッケージをリポジトリから取り寄せたり、developの対象から外したりできます。
プロジェクト直下にsrcディレクトリを作成します。 これから作成するguestbookアプリケーションのためのディレクトリを作成して、setup.pyを書きましょう。
$ mkdir -p src/guestbook
src/guestbook/setup.py:
from setuptools import setup, find_packages requires = [ "Zope2", "five.grok", ] setup(name="guestbook", install_requires=requires, packages = find_packages() )
mr.developerをbuildoutに追加します。
buildout.cfg:
[buildout] extensions = mr.developer [sources] guestbook = fs guestbook
guestbookをinstanceのeggsに追加します。 直接buildout.cfgに追加してもよいですが、guestbook用の設定ファイルを新しく作成して、元のbuildout.cfgを拡張するようにしてみましょう。
guestbook.cfg:
[buildout] auto-checkout = guestbook [zope2] eggs += guestbook
buildoutで、buildout.cfg以外の設定ファイルを使う場合は -c オプションを使います。
$ buildout -c guestbook.cfg
これでguestbookアプリケーションを開発する準備が整いました。
Guestbookアプリケーション
Zope2のアプリケーションは単にZODB上に保存されるオブジェクトです。 が、ZMIから追加できるように登録したり、コンポーネントの構成を登録したりとめんどうが多いので、five.grokを利用してさっくりといきましょう。
まずは guestbookプロジェクトにguestbookパッケージを作ります。
$ mkdir -p src/guestbook/guestbook $ touch src/guestbook/guestbook/__init__.py
app.py にアプリケーションを実装します。
src/guestbook/guestbook/app.py:
from datetime import datetime from five import grok from persistent.list import PersistentList class Guestbook(grok.Model): meta_type = 'guestbook' def __init__(self, *args, **kwargs): super(Guestbook, self).__init__(*args, **kwargs): self.greetings = PersistentList() def add_comment(self, name, comment): greeting = dict(name=name, comment=comment, create_at=datetime.now()) self.greetings.append(greeting)
add_comment メソッドがゲストブックに情報を書きこむメソッドです。 オブジェクトデータベースなので、これだけで情報は保存されます。 meta_typeはZope2のZMI上で表示される文字列です。 あとは、ビューが必要です。 これらも app.py に実装しましょう。 モデルと同じモジュール内でビューを実装すると、モデルとビューの対応付けが自動で行われます。
src/guestbook/guestbook/app.py 後半:
class Index(grok.View): pass class Post(grok.View): def update(self, name, comment): self.context.add_comment(name, comment) def render(self): return self.redirect(self.url(self.context))
Indexクラスは、単にcontextを表示するだけなので、なにもメソッドを持ちません。 Postクラスはフォームの入力を受けて、Guestbookのadd_commentを呼び出すビューです。 updateメソッドで実際の処理を行い、renderメソッドで元の画面にリダイレクトしています。
テンプレート
ビュークラスは、HTMLの生成は受け持っていません。 Postクラスではrenderメソッドをオーバーライドしているため、レスポンスボディの生成されないため、IndexクラスのHTMLテンプレートだけが必要です。
five.grokではgrok.Viewを継承している場合、 {モジュール名}_templates/{クラス名}.pt というテンプレートが自動で利用されます。 appモジュールの Indexクラスの場合は app_templates/index.pt となります。
テンプレートの内容は https://github.com/aodag/zope2-guestbook/blob/master/guestbook/app_templates/index.pt をみてください。
configure.zcml
さて、アプリケーションの実装ができたので、これらをコンポーネント登録します。 Zope3スタイルでは上記のクラスを全部configure.zcmlで登録することになりますが、five.grokを使っているので、1行のディレクティブで済ませることができます。
src/guestbook/guestbook/configure.zcml:
<configure xmlns="http://namespaces.zope.org/five" xmlns:grok="http://namespaces.zope.org/grok"> <include package="five.grok"/> <grok:grok package="."/> </configure>
ZMIに追加する
アプリケーションを実装して、コンポーネントへの登録もできました。 あとは、ZMIへの登録です。
ZMIはZope2固有の機能なので、それに従わなくてはなりません。
src/guestbook/guestbook/__init__.py:
from Products.PageTemplates.PageTemplateFile import PageTemplateFile from . import app def addGuestbook(context, id, title): """ add new guestbook """ guestbook = app.Guestbook(id) guestbook.title = title context._setObject(id, guestbook) return "OK" manage_addGuestbookForm = PageTemplateFile('manage_addGuestbook', globals()) def initialize(registrar): registrar.registerClass( app.Guestbook, constructors=(manage_addGuestbookForm, addGuestbook))
アプリケーションクラスと、追加するためのフォームとアクションをregistrarで登録します。 後はこの関数を configure.zcml に追加します。
src/guestbook/guestbook/configure.zcml 最終形:
<configure xmlns="http://namespaces.zope.org/five" xmlns:grok="http://namespaces.zope.org/grok"> <registerPackage package="." initialize=".initialize"/> <include package="five.grok"/> <grok:grok package="."/> </configure>
ZMIからの追加
ここまできたら Zope2 を再起動します。 ZMIからguestbookを追加すれば、Guestbookアプリケーションを利用できます。
まとめ
めんどい
Comments !