Python/Werkzeug
提供:やる気向上作戦
目次 |
Werkzeugでウェブアプリケーションを作る
Werkzeugって何?
WSGIアプリケーションを構築するための便利なツールキット。いわゆるフレームワークではない。
作者はJinja(Djangoクローンのテンプレートエンジン)やPocoo(Python製ウェブフォーラムアプリケーション)と同一。
基本構造
最小のアプリケーションは、
- アプリケーションクラス
- URLマップ
- ビュー関数
- ドライバ
からなる。
app.py
アプリケーションクラスを実装。
from werkzeug import Request, ClosingIterator
from werkzeug.exceptions import HTTPException, InternalServerError
# URLマップをインポート
from urls import url_map
# ビュー関数をインポート
import views
# アプリケーションクラス
class Application(object):
def __init__(self):
pass
def __call__(self, environ, start_response):
try:
self._setup()
# 環境オブジェクトを与えて、リクエストをオブジェクトを作成
request = Request(environ)
# urls.pyで定義したURLマップを使って、リクエストされたURLにマッチするビュー関数を取得
adapter = url_map.bind_to_environ(environ)
endpoint, values = adapter.match()
handler = getattr(views, endpoint)
# ディスパッチ
response = handler(request, **values)
except HTTPException, e:
response = e
except:
response = InternalServerError()
# 以下のコードでも可。
# return response(environ, start_response)
# しかし、ClosingIteratorを用いることで、レスポンスを返し終わった後に、
# クリーンアップメソッド(self._cleanup)を呼ぶことが可能になる。
return ClosingIterator(
response(environ, start_response), self._cleanup)
def _setup(self):
# リクエストディスパッチ前に実行する初期化処理
pass
def _cleanup(self):
# リクエストディスパッチ後に実行するクリーンアップ処理
pass
urls.py
URLマップを実装。
from werkzeug.routing import Map, Rule
# Ruleの最初の引数には、URLのパターンを記述。
# キーワード引数endpointは、views.pyにおけるビュー関数の名前。
url_map = Map([
Rule("/", endpoint="index"),
])
views.py
ビューを実装。
from werkzeug import Response
def index(request):
return Response("Hello, world!", mimetype="text/plain")
index.cgi
ドライバ。ここではCGIから起動されることを想定。flupを使えば、FastCGIサーバとして起動することも容易。
#!/usr/bin/python
from wsgiref.handlers import CGIHandler
from werkzeug import DebuggedApplication
from app import Application
if __name__ == '__main__':
CGIHandler().run(Application())
# デバッガを有効にする場合は、DebuggedApplicationでラップする
# CGIHandler().run(DebuggedApplication(Application()))
テンプレートエンジン(Jinja)を使う
テンプレートエンジンを利用することで、ビュー(というかHTML)とロジック(というかデータモデル)の分離が容易になる。ここでは、Werkzeugの作者の別の作品であるJinjaをテンプレートエンジンとして利用することにする。
Jinjaは、テンプレートをロードするための環境オブジェクトを必要とする。典型的なアプリケーションでは、アプリケーションスタート時に、一つだけ環境オブジェクトを作成し、以降はそれを使いまわす。
Werkzeugアプリケーションのビュー関数から共通的に環境オブジェクトを利用できるように、resource.pyを作成する。また、テンプレートを利用するようにviews.pyを書き換える。
resouces.py
from jinja import Environment, FileSystemLoader
# ファイルシステム上のディレクトリからテンプレートをロードする環境オブジェクトを作成
tpl_env = Environment(loader=FileSystemLoader("/path/to/a/directory"))
views.py
from werkzeug import Response
# 環境オブジェクトをインポート
from resources import tpl_env
def index(request):
# 環境オブジェクトを利用して、テンプレートオブジェクトを得る
tpl = tpl_env.get_template("index.html")
# テンプレートオブジェクトによりレンダリングされたHTMLを返す。
return Response(tpl.render(msg="Hello, world!"), mimetype="text/html")
index.html
テンプレート本体。
<html>
<head>
<title>Index</title>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
</head>
<body>
{{ msg|e }}
</body>
</html>
データベースツールキット(SQLAlchemy)を使う
resouces.py
from jinja import Environment, FileSystemLoader
from sqlalchemy import create_engine, MetaData
from sqlalchemy.orm import sessionmaker, scoped_session
# ファイルシステム上のディレクトリからテンプレートをロードする環境オブジェクトを作成
tpl_env = Environment(loader=FileSystemLoader("/path/to/a/directory"))
# データベースエンジン、メタデータ、およびセッションクラスを作成
db_engine = create_engine("sqlite:////path/to/a/db/file")
db_metadata = MetaData()
db_session_class = scoped_session(
sessionmaker(bind=db_engine, autoflush=True, transactional=True))
models.py
モデルを実装。
from resources import db_metadata
from resources import db_session_class
from sqlalchemy import Table, Column, Integer, String
model_table = Table("models", db_metadata,
Column("id", Integer, primary_key=True),
Column("name", String(100))
)
class Model(object):
pass
db_session_class.mapper(Model, model_table)