読者です 読者をやめる 読者になる 読者になる

神社参拝(1)

Python Jinja

元日といえば初詣、初詣と言えば神社。Python愛好家にとっての神社と言えば、Jinja2しかないということで、Jinja2に触ってみる。Djangoテンプレートとの違いはここに簡潔にまとまっているが、ドキュメントをざっと目を通して、気づいたところをメモしていく。

TemplateとEnvironment

Jinjaの最も単純な使い方としては、次のようにテンプレート文字列を与えてTemplateオブジェクトを生成し、renderで出力というものだろう。

>>> from jinja2 import Template
>>> tmpl = Template("Hello, {{ name }}")
>>> tmpl.render(name="World")
u"Hello, World"

実際にはファイルシステム上にテンプレートファイルを置くのが普通だろう。ファイルシステム等からテンプレートを読み込むにあたって、その読み込み方法(TemplateLoader)や最適化、キャッシュ等の設定を保持しているのが、Environmentオブジェクト。例えば、/path/to/templatesというディレクトリに置いたテンプレートファイルを読み込むには、

from jinja2 import Environment, FileSystemLoader
env = Environment(
    loader=FileSystemLoader('/path/to/templates', encoding='utf8'),
    autoescape=True
    )
tmpl = env.get_template('index.html')
tmpl.render(name="World")

自動HTMLエスケープ

Djangoのテンプレートシステムと同じように自動HTMLエスケープ機能がある。この機能はデフォルトではオフなので、Template, Environmentを生成するときに、autoescape=Trueとして明示的に有効にしなくてはならない。

>>> from jinja2 import Template
>>> tmpl = Template("Hello, {{ name }}", autoescape=True)
>>> tmpl.render(name=u"<World>")
u'Hello, &lt;World&gt;'

autoescape=Trueなテンプレートで、エスケープを無効にするには、safeフィルタを使う。これはDjangoと同じ。

>>> from jinja2 import Template
>>> tmpl = Template("Hello, {{ name|safe }}", autoescape=True)
>>> tmpl.render(name=u"<em>World</em>")
u'Hello, <em>World</em>'

テンプレートのデリミタを変える

Template, Environmentオブジェクト生成時にblock_start_string, block_end_string, variable_start_string, variable_end_stringを指定すると、テンプレートのデリミタを好みのものに変更できる。例えば、erb風にするならば、

>>> from jinja2 import Template
>>> tmpl = Template("Hello, <%= name %>", variable_start_string='<%=', variable_end_string='%>')
>>> tmpl.render(name="World")
u'Hello, World'

継承

Djangoと同じように{% extends %}でテンプレートの継承を行えるが、Djangoのように親テンプレートのブロックを上書きしてしまうのではなく、親テンプレートのブロックの出力の内容に付け加えて子テンプレートで何かを出力するということができるようになっている。

上の書き方だと良く分からない(僕もなんと書けばよいかぱっと思いつかない)けど、具体例で言うと、Djangoでは次のようなテンプレートは書けないが、Jinjaでは書ける。

{# 親テンプレート(parent.html) #}
<html>
<head>
{% block head %}
 <title>{% block title %}{% endblock %}</title>
 {# headブロックの中にtitleブロックが内包されている #} 
{% endblock %}
</head>
<body></body>
</html>
{# 子テンプレート #}
{% extends "parent.html" %}
{% block title %}title comes here{% endblock %}
{% block head %}
 {{ super() }}
 <style type="text/css">
   ....
 </style>
{% endblock %}
</head>
<body></body>
</html>

出力結果は、

<html>
<head>
{% block head %}
 <title>title comes here</title>
 <style type="text/css">
   ....
 </style>
</head>
<body></body>
</html>

制御構文({% if %})

Jinjaでは{% if %}{% elif %}に式を書けるので便利。

{% if value == "spam" %}
  <h1>SPAM</h2>
{% elif value == "egg" %}
  <h1>EGG</h1>
{% else %}
  <h1>HAM</h1>
{% endif %}