Pyramidでテンプレートを使う
Pyramid チュートリアル — Pyramid Tutorial for PyCon JP Sprint 1.0 documentation にテンプレートエンジンを使用して HTML の表示を行う項目があったのでやってみた.
このチュートリアルでは mako テンプレートというものを使うらしい.
makoテンプレートを使うために、 Configuratorにテンプレートが置かれているディレクトリを指定します。 まずは、テンプレート用のディレクトリを作成しましょう。
まずテンプレートを配置するディレクトリを作る.
$ mkdir templates
次にテンプレートとして使う index.mak を templates に作成する.
<html> <body> <h1>Hello, ${name}</h1> </body> </html>
文中に ${ と } で囲まれた文字列があるが,
name 変数を表示するテンプレートです。 ${ と } で囲まれた部分は、pythonの式として評価されて、結果がHTML中に表示されます。
ということだ.結果をそのまま表示できるのは嬉しい.
次にこのテンプレートを表示させるための templating.py を作成する.
from waitress import serve from pyramid.config import Configurator from pyramid.view import view_config @view_config(route_name="home", renderer="index.mak") def index(request): return dict(name="pyramid") if __name__ == '__main__': import os here = os.path.dirname(__file__) settings = { 'mako.directories':[ os.path.abspath(os.path.join(here, 'templates')), ], } config = Configurator(settings=settings) config.add_route('home', '/') config.scan() app = config.make_wsgi_app() serve(app, host='0.0.0.0')
$ python templating.py serving on http://0.0.0.0:8080 ... ValueError: No such renderer factory .mak
表示されない.
pyramid_mako のインストール
調べてみると ここ に解決方法があった.
config = Configurator(settings=settings) config.include('pyramid_mako') # < added that config.add_route('home', '/')
pyramid_mako を include しろという.
ただ pyramid_mako なんてものは入っていないので pip を使って入れる.
$ pip install pyramid_mako ... Successfully built pyramid-mako Mako MarkupSafe Installing collected packages: MarkupSafe, Mako, pyramid-mako Successfully installed Mako-1.0.4 MarkupSafe-0.23 pyramid-mako-1.0.2
動かしてみる.
$ python templating.py serving on http://0.0.0.0:8080
localhost:8080 を見ると Hello, pyramid と表示された.
resource context
ビュー関数はあくまでビューなので、ここにロジックを書くのは推奨されません。 リソースを定義して、そちらにロジックを書きましょう。 また、リソースはリクエストごとに生成されたり、ロードされたりします。 リクエストに対応するリソースは、 context として、 request から取得できます。
処理はビューにベタ書きせずに別に書いてねってことみたい.
templating.py をチュートリアルに沿って編集する.
from datetime import datetime, date from waitress import serve from pyramid.config import Configurator from pyramid.view import view_config from pyramid.response import Response class MyContext(object): def __init__(self, request): self.request = request def get_date(self): return date.today() def greeting(self): now = datetime.now() if now.hour < 12: return "Good morning" elif now.hour < 18: return "Good afternoon" else: return "Good evening" @view_config(route_name="home", renderer="index.mak") def index(request): return dict() if __name__ == '__main__': import os here = os.path.dirname(__file__) settings = { 'mako.directories':[ os.path.abspath(os.path.join(here, 'templates')), ], } config = Configurator(settings=settings, root_factory=MyContext) config.include('pyramid_mako') # < added that config.add_route('home', '/') config.scan() app = config.make_wsgi_app() serve(app, host='0.0.0.0')
index.mak の方にも変更を加える.
<html> <body> ${request.context.get_date()} ${request.context.greeting()} </body> </html>
これだとオブジェクトを共有しちゃうじゃんと思ったら書いてあった.
route ごとに異なるリソースを使いたい場合は、 add_route のキーワード引数 resource_factory にクラスや関数を渡します。
add_route の引数 resource_factory に渡せばいいらしい.
と思ったら resource_factory という引数はない.ドキュメント を見てみると引数 factory に渡せば良さそう.
add_route(name, pattern=None, view=None, view_for=None, permission=None, factory=None, for_=None, header=None, xhr=None, accept=None, path_info=None, request_method=None, request_param=None, traverse=None, custom_predicates=(), view_permission=None, renderer=None, view_renderer=None, view_context=None, view_attr=None, use_global_views=False, path=None, pregenerator=None, static=False, **predicates)
以下を templatig.py に追加した.
class MyContext2(object): def __init__(self, request): self.request = request def hello(self): return "Hello World" @view_config(route_name="test", renderer="test.mak") def test(request): return dict() # main config.add_route('test', '/test', factory=MyContext2)
templates に test.mak を作成する.
<html> <body> ${request.context.hello()} </body> </html>
home は MyContext を使い,test は MyContext2 を使う.
うまく分けることができた.