通常Bottleを使用する場合は、使用するテンプレートに併せて必要なメソッドやデコレータをインポートして用いることで、viewテンプレートの描画を非常に簡単に行うことが出来ます。
例えば、Jinja2テンプレートを使用し、メソッドでviewテンプレートの描画を行う場合は以下のようになります。
from bottle import route, jinja2_template as template @route('/') def index(): return template('index.html', data = some_func())
また、同様の処理をデコレータで実装すると以下のようになります。
from bottle import route, jinja2_view as view @route('/') @view('index.html') def index(): return dict(data=some_func())
このメソッド群は非常に便利ですが、細かいセッティングをしようとすると、少なくない問題が発生します。
例えば、テンプレート側で何らかの関数を利用したい場合、jinja2.Environment
のglobals
に追加しますが、bottleに用意されているメソッドでそれを実装するのは少々難しいです(そこまでソースコードを読んでいないので可能かもしれません)。
というわけで、templateの展開を行うviewデコレータを自力で実装してしまえという結論に至ります。
環境
Bottle v0.12
Jinja2 v2.8
実装
新しいview用のファイルをdecoview.pyという名前で作成し、以下のようにします。
# decoview.py import functools import jinja2 env = jinja2.Environment( loader=jinja2.FileSystemLoader('./path/to/views'), autoescape = True ) env.globals.update({ 'some_func_key', some_func() }) def some_func(): return 'Called some_func!' def view(template_name): def decorator(view_func): @functools.wraps(view_func) def wrapper(*args, **kwargs): response = view_func(*args, **kwargs) if isinstance(response, dict): template = env.get_or_select_template(template_name) return template.render(**response) else: return response return wrapper return decorator
せっかくなのでautoescape
もTrue
にしてみました。
新しく作成したdecoviewをインポートして使用すれば、jinja2テンプレートファイルの中でsome_func()
が実行可能です。
# index.py from bottle import route from decoview import view @route('/') @view('index.html') def index(): return {}
例えば下記のようにjinja2テンプレートを呼び出します。
<!-- index.html -->
{{ some_func_key }}
きっとCalled some_func!
という文字列が表示されていることと思います。
参考
API — Jinja2 Documentation (2.8-dev)
Jinja2 templates and Bottle | Reliably Broken