Python Web フレームワークアドベントカレンダー の 7 日目担当の、ふるかわとおるです。よろしくお願いします。
あのですね。Python 3.x みんな使わないんですよねぇ。やっぱり、それなりのことをやりたくなると、サードパーティのライブラリに依存することになるんですが、そのライブラリが 3.x 対応じゃないと、なかなか乗り換えられませんよね。特にウェブの場合は、文字列まわりの変更の影響が大きいですし、WSGI の次期仕様である PEP444 が確定してないこともあったりで、軒並み Python 3.x 対応していません。http://python.org/3kpoll を見ると、Python 3.x 対応してほしいランキング 1位が Django ですね。私も1票投じているわけですが。
さてさて、そんなわけで、ここでは Python 3.x に対応しているウェブフレームワーク QP を紹介します。Mac OS X 10.6.5 でビルドした Python 3.2 を使いました。紹介といいつつも、ドキュメントがほとんどないので、必死でサンプルを読み解いた軌跡です。やべぇ、もう 23:22。
インストール
setuptools では、途中のビルドに失敗するので、Distribute を先にインストールします。
$ python3.2 setup.py install
つづいて、
$ easy_install-3.2 durus $ easy_install-3.2 qpy $ easy_install-3.2 qp
durus は ZODB っぽいデータストレージ、qpy はテンプレートエンジンです。qp は Quixote の後継フレームワークなんですけど、23:27 になったので次。
Hello world!
qp のプロジェクトは、配置する場所が決まっています。/var/qp_sites とか。あるいは環境変数 QP_SITES に格納されたパスに置いておきます。
ここでは qp_sites/hello ディレクトリをまず作ります。必要なファイルがいくつか必要です。
- qp_sites/hello/__init__.py ... からっぽで OK
- qp_sites/hello/var ... 空っぽのディレクトリ。pid ファイルとかが置かれる。
- qp_sites/hello/slash.py ... ここにコードかく
では、slash.py を見ましょう。
from qp.pub.publish import Publisher
from qp.fill.directory import Directory
class SitePublisher (Publisher):
configuration = {"http_address":("", 8000)}
class SiteDirectory (Directory):
def get_exports(self):
yield ("", "index", "top page", "Home page of hello") # パス、メソッド名、名前、タイトルのタプル
def index(self):
return "hello, world"
ターミナルから
qp -u hello
で、起動します。
テンプレートエンジン使う準備
変更するファイルがトリッキーです。まず、slash.py を slash.qpy にリネームして、以下のように編集します。
# qp_sites/hello/slash.qpy
from qp.pub.publish import Publisher
from qp.fill.directory import Directory
class SitePublisher (Publisher):
configuration = {"http_address":("", 8000)}
class SiteDirectory (Directory):
def get_exports(self):
yield ("", "index", "top page", "Home page of hello")
def index [html] (self):
header("Hello!") # <html><head> ... とかを出力してくれる
"<strong>Hello,</strong> <em>World!</em>"
footer() # </body></html>を出力してくれる
つづいて、__init__.py も編集。
#__init__.py
from qpy.compile import compile_qpy_files
compile_qpy_files(__path__[0])
.qpy は、微妙に Python とはことなってて、def index [html] (self) あたりが拡張されています。テンプレートエンジン qpy はこのファイルをコンパイルしたものを使います。なので、テンプレート書き換えたら、qp を再起動します。
qp restart
index メソッドがテンプレートになっていて、各行を評価した結果の文字列が、テンプレートの出力になります。
header() の戻り値、"<strong>Hello,</strong> <em>World!</em>"、footer() の戻り値が連結されて、レスポンスになります。
テンプレートと永続化を使う
わたくし、ちょうど1年くらい前にウェブ業界にはいりまして、データベースとか詳しくないんですよねぇ。なので、MySQL とかとつなぐとかめんどくさくって。qp なら durus というオブジェクト永続化の仕組みをつかえるので楽ちんです。ZODB を知ってる人ならなじめるらしいです。
# qp_sites/hello/slash.qpy
from qp.pub.common import header, footer, get_publisher
from qp.pub.publish import DurusPublisher
from qp.fill.directory import Directory
from durus.persistent import PersistentObject
class SitePublisher (DurusPublisher):
configuration = {"http_address":("", 8000)}
def count_up(self):
d = self.get_root()
d['count'] = d.get('count', 0) + 1
self.commit()
return d['count']
class SiteDirectory (Directory):
def get_exports(self):
yield ("", "index", "top page", "Home page of hello")
def index [html] (self):
header("Hello")
"<strong>Hello,</strong> <em>World!</em>"
"<p>"
get_publisher().count_up()
"</p>"
footer()
データは SitePublisher クラスのプロパティとして格納されます。でデータは基本的にツリー構造になっていて、ツリーの根をとるのが、get_root() メソッドで辞書っぽいオブジェクトを返します。これに任意のオブジェクトを追加して、commit() メソッドを実行すると、データが保存できます。上の例では、 count_up() メソッドがそれです。
てな感じですね。
まとまらないまとめ
テンプレートが 似非 Python コードであること、データの保存がオブジェクト永続化であること、あたりが、メジャーどころと大きくことなる QP ですが、ちょっと気になっています。durus はマルチスレッド、マルチプロセスに対応している雰囲気です。そんなわけで、QP と Python 3.x 、これからも気にしていこうと思います。
つぎは、Python 界のイケメン地ビール愛好家 @MiCHiLU さんにお願いしまっす。