.. _topics-templates:
.. _The Django template language:
============================
Django テンプレート言語
============================
:revision-up-to: 17821 (1.4)
.. admonition:: このドキュメントについて
このドキュメントでは、Django テンプレートシステムの文法について説明して
います。技術的な観点からのテンプレートシステムの仕組みや拡張方法に関す
る説明は、 :doc:`/ref/templates/api` を参照してください。
Django のテンプレート言語は、釣合いの取れたパワーと簡便さを実現するように、
また HTML を扱いなれた人にとっては快適になるように設計されています。
Smarty_ や CheetahTemplate_ のようなテキストベースのテンプレート言語を経験
したことがあるなら、 Django のテンプレートはしっくりくるはずです。
.. admonition:: 設計哲学
:class: admonition-philosophy
プログラミングの知識があったり、 PHP のようなプログラムコードを直接
HTML に混ぜ込む言語を使ったことがあるなら、 Django のテンプレートシステ
ムが単に HTML に Python を埋め込んだものでないことに疑問を持つでしょう。
しかし、これは設計上意図して決まっていることです。テンプレートシステム
はプレゼンテーション層を表現するためのもので、プログラムロジックではな
いのです。
Django のテンプレートシステムは、プログラムの構成部品に似たタグ、例えば
ブールテストのための :ttag:`if` タグやループ処理のための :ttag:`for`
タグを備えています。しかし、これらのタグは単に同じ意味の
Python コードとして実行されるのではなく、テンプレートシステムは Python
の式を解釈実行したりはしません。テンプレートシステムがサポートしている
のは、以下で定義されているデフォルトのタグ、フィルタおよびその構文だけ
です (もちろん、必要に応じてテンプレート言語を
:doc:`拡張する ` のは可能です)。
.. _`The Django template language: For Python programmers`: ../templates_python/
.. _Smarty: http://smarty.php.net/
.. _CheetahTemplate: http://www.cheetahtemplate.org/
テンプレート
============
.. highlightlang:: html+django
テンプレートは単なるテキストファイルでできています。 テンプレートはあらゆる
テキストベースのデータ形式 (HTML, XML, CSV など) を生成できます。
テンプレートには、テンプレートを処理する際に実際の値に置き換えられる
**変数 (variable)** と、テンプレート上でロジックを制御する **タグ (tag)**
が入っています。
以下に示すのは、基本的な項目をいくつか組み込んだ最小限のテンプレートです。
各項目についてはこのドキュメントの後の部分で詳しく説明します::
{% extends "base_generic.html" %}
{% block title %}{{ section.title }}{% endblock %}
{% block content %}
{{ section.title }}
{% for story in story_list %}
{{ story.tease|truncatewords:"100" }}
{% endfor %}
{% endblock %}
.. admonition:: 設計哲学
:class: admonition-philosophy
なぜ (Zope における TAL のような) XML ベースのテキストベースのテンプレー
トではなく、テキストベースのテンプレートを使うのでしょうか ? それは、
Django のテンプレート言語を XML/HTML テンプレート以外にも使いたいと考え
ているからです。 World Online では、email や JavaScript、 CSV にテンプ
レートを使っています。テンプレートはテキストベースの形式なら何にでも使
えるのです。
そう、もう一つあります: 人間に XML を編集させるなんて、サディスティック
でしかありません!
変数
====
変数 (variable) は ``{{ variable }}`` のような形式になります。テンプレート
エンジンが変数名を見つけると、変数を評価して値を置き換えたものを出力します。
変数名は英字と数字とアンダースコア(``"_"``)の組み合わせです。ドット(``"."``)
も変数のなかに出現します、ですがそれには特別な意味があり、それは下記に示すと
おりです。
大切なことは、 *変数名の中にスペースを入れたり句読点を含まないことです*
変数の属性値にアクセスするには、ドット (``.``) 表記を使います。
.. admonition:: 舞台裏
技術的には、テンプレートシステムが dot を見つけた場合、以下の順で値の評
価を試みます:
* 辞書の照合 (lookup)
* 属性の照合
* メソッドの呼び出し
* リストをインデクス指定して照合
上の例では、 ``{{ section.title }}`` は ``section`` オブジェクトの
``title`` 属性に置き換えられます。
実在しない変数を使うと、テンプレートシステムは :setting:`TEMPLATE_STRING_IF_INVALID`
の設定値を挿入します。デフォルトの値は ``''`` (空文字列) です。
フィルタ
========
変数を表示するために手を加えたい場合には **フィルタ (filter)** を使います。
フィルタは ``{{ name|lower }}`` のように書きます。この例では、変数 ``{{
name }}`` の値は :tfilter:`lower` フィルタ、すなわち文字を小文字に変換するフィルタ
を通してから表示します。フィルタの適用は (``|``) で表します。
フィルタは「連鎖 (chain)」できます。フィルタを連鎖させると、あるフィルタか
らの出力を別のフィルタに渡せます。例えば、 ``{{ text|escape|linebreaks }}``
は、テキストの内容をエスケープして、改行を ```` タグに置き換える時の慣用
句としてよく使われています。
フィルタによっては引数をとります。フィルタの引数は
``{{ bio|truncatewords:"30" }}`` のような形式で表します。この例では、変数
``bio`` の最初の 30 語を表示します。
フィルタの引数にスペースが入っている場合は、二重引用符で囲ってください。例
えば、カンマとスペースでリストを結合するには ``{{ list|join:", " }}``
のようにします。
:ref:`組み込みフィルタリファレンス` では、
全ての組み込みフィルタについて説明しています。
組み込みフィルタでできることを知ってもらうために、よく使うテンプレートフィ
ルタをいくつか挙げましょう:
:tfilter:`default`
入力が空や ``False`` の場合、引数に指定したデフォルト値を使いま
す。そうでなければ、入力をそのまま使います
使用例::
{{ value|default:"nothing" }}
``value`` が存在しなかったり空だったりすると、 "``nothing``" を出力
します。
:tfilter:`length`
入力値の長さを返します。文字列とリストいずれにも作用します。
使用例::
{{ value|length }}
``value`` が ``['a', 'b', 'c', 'd']`` なら、 ``4`` を出力します。
:tfilter:`striptags`
[X]HTML タグを全てはぎとります。
使用例::
{{ value|striptags }}
``value`` が
``"Joel a slug"``
なら、 ``"Joel is a slug"`` を出力します。
これらはほんの一部に過ぎません。全ての組み込みフィルタの一覧は
:ref:`組み込みフィルタリファレンス ` を参照
してください。
テンプレートフィルタは自作できます。 :doc:`/howto/custom-template-tags`
を参照してください。
.. seealso::
Django のアドミンインターフェイスはすべてのテンプレートタグと
利用可能なフィルタに関してはこちらのサイトで完全な参照を得られます。
:doc:`/ref/contrib/admin/admindocs`
タグ
====
タグは ``{% tag %}`` のように書きます。タグの考え方は、変数よりもやや複雑
です。出力されるテキストを生成するものもありますし、ループやロジックを実行
して、処理の流れを制御するものもあります。また、外部の情報を取り込んで、後
に出て来る変数から使えるようにするものもあります。
タグによっては、開始タグと終了タグ
(``{% tag %} ... tag contents ... {% endtag %}``) を必要とするものがありま
す。
Django にはたくさんの組み込みタグが付属しています。組み込みタグの解説は
:ref:`組み込みタグリファレンス ` にあります。
組み込みタグでできることを知ってもらうために、よく使うタグをいくつか挙げま
しょう:
:ttag:`for`
アレイの各要素に渡ってループします。例えば、アスリート (athlete) の
リストを ``athlete_list`` で渡して表示するには、以下のようにします::
{% for athlete in athlete_list %}
- {{ athlete.name }}
{% endfor %}
:ttag:`if` and :ttag:`else`
変数を評価して、値が「真」 (値が存在して、空の配列でなく、ブール値
が偽でない) の場合、ブロック内のコンテンツを出力します::
{% if athlete_list %}
Number of athletes: {{ athlete_list|length }}
{% else %}
No athletes.
{% endif %}
上の例では、 ``athlete_list`` が空でなければ、アスリートの人数を
``{{ athlete_list|length }}`` で表示します。
:ttag:`if` タグの中で、他のフィルターや変数を使うにはを使うこともできます。::
{% if athlete_list|length > 1 %}
Team: {% for athlete in athlete_list %} ... {% endfor %}
{% else %}
Athlete: {{ athlete_list.0.name }}
{% endif %}
:ttag:`block` and :ttag:`extends`
`テンプレートの継承`_ は、テンプレート内の"繰り返し" を減らすことができます。
これらはほんの一部に過ぎません。全ての組み込みフィルタの一覧は
:ref:`組み込みタグリファレンス ` を参照してく
ださい。
テンプレートタグは自作できます。 :doc:`/howto/custom-template-tags`
を参照してください。
.. seealso::
Djangoのアドミンインターフェイスはすべてのテンプレートタグと
利用可能なフィルタに関してはこちらのサイトで完全な参照を得られます。
:doc:`/ref/contrib/admin/admindocs`
コメント
========
テンプレート中で行内の一部をコメントアウトするには、コメント構文 ``{# #}``
を使います。
例えば、以下のテンプレートをレンダすると ``'hello'`` になります::
{# greeting #}hello
コメント内には任意のテンプレートコードを入れられます。コメント内の
テンプレートコードが無効なものであってもエラーにはなりません::
{# {% if foo %}bar{% else %} #}
この構文を使えるのは、一行のコメントの場合だけです (``{#`` と ``#}`` の間に
は改行を入れられません)。複数行のコメントアウトを行いたければ、後述の
:ttag:`comment` タグを使ってください。
.. _template-inheritance:
テンプレートの継承
==================
Django のテンプレートエンジンにおいて、テンプレートの継承 (inheritance) は
最もパワフル -- かつ最も難解 -- な部分です。テンプレートの継承は、自分のサ
イトで共通に使われる全ての要素の入った、ベースとなる「骨組みの」テンプレー
トを作っておき、その中に子のテンプレートでオーバライドできる
**ブロック(block)** を定義できます。
テンプレートの継承を理解するには、まず例を挙げるのが一番でしょう::
{% block title %}My amazing site{% endblock %}
{% block content %}{% endblock %}
このテンプレートは、単純な 2 カラム形式のページで使うような HTML のスケルト
ンドキュメントです。これを ``base.html`` と呼びましょう。空のブロックをコン
テンツで埋めるのは「子 (child)」のテンプレートの仕事です。
この例では、 :ttag:`block` タグを使って 3 つのブロックを定義し、子テンプ
レートが値を埋められるようにしています。 :ttag:`block` タグの役割は、テンプレー
ト中のタグで囲まれた部分を子テンプレートでオーバライドできることをテンプレー
トエンジンに知らせることにあります。
子テンプレートは以下のようになります::
{% extends "base.html" %}
{% block title %}My amazing blog{% endblock %}
{% block content %}
{% for entry in blog_entries %}
{{ entry.title }}
{{ entry.body }}
{% endfor %}
{% endblock %}
:ttag:`extends` タグが継承のカギです。このタグはテンプレートエンジンに対
して、自分自身が他のテンプレートを拡張 (extend) していることを教えます。テ
ンプレートシステムがこのテンプレートを処理する際、システムはまず親となるテ
ンプレート -- ここでは "base.html" を探します。
さて、この時点で、テンプレートエンジンは ``base.html`` 内に三箇所の
:ttag:`block` が定義されていることに気づき、これらのブロックを子テンプレー
トの該当するブロックで置き換えます。 ``blog_entries`` の値に応じて、出力は
以下のようになります::
My amazing blog
Entry one
This is my first entry.
Entry two
This is my second entry.
子テンプレートには ``sidebar`` ブロックが定義されていないので、親テンプレー
トの値がそのまま使われます。親テンプレートの ``{% block %}`` タグの内容は、
常にフォールバックの値として使われます。
テンプレートの継承は必要に応じて何段階にもできます。継承を使うよくある場合
の一つに、以下のような三段階のアプローチがあります:
* サイトの主なルック & フィールを決める ``base.html`` テンプレートを作
成します。
* サイトの各「セクション」ごとに ``base_SECTIONNAME.html`` テンプレート
を作成します。たとえば、 ``base_news.html`` , ``base_sports.html`` と
いった具合です。これらのテンプレートでは ``base.html`` を拡張して、セ
クション固有のスタイルやデザインを取り込んでおきます。
* ニュース記事やブログエントリといった各種ページ用の個々のテンプレート
を作成します。これらのテンプレートでは適切なセクションテンプレートを
拡張します。
このようなアプローチを取れば、コードの最利用性を最大限に高め、セクション毎
のナビゲーションのような項目を簡単に共通のコンテンツ領域に追加できます。
継承を扱うときの小技をいくつか挙げておきます:
* テンプレートで :ttag:`{% extends %}` を使う場合は、テンプレート中の最初の
テンプレートタグにせねばなりません。さもなければテンプレート継承はう
まく動作しません。
* ベースのテンプレートで :ttag:`{% block %}` を多用すればするほど、よりよい
テンプレートになります。子テンプレートは親テンプレートのブロックを必
ずしも全て定義しなくてもよいことを思い出して下さい。ブロックをたくさ
ん用意しておき、適切なデフォルト値を入れておいて、子テンプレートで必
要な値だけを再定義すればよいのです。フックは少ないよりも沢山ある方が
よいのです。
* 同じような内容を含むテンプレートをいくつも作っていることに気づいたら、
それはすなわちその内容を親テンプレートの ``{% block %}`` に入れるべき
だということです。
* 親テンプレートのブロックに入っているコンテンツを取り出す必要がある場
合、 ``{{ block.super }}`` とするとうまくいきます。親テンプレートのブ
ロックをオーバライドするのではなく、内容を追加したい場合に便利です。
``{{ block.super }}`` で挿入されたデータは、通常、親テンプレートで
既にエスケープされているので、自動的にエスケープされません
(:ref:`automatic-html-escaping` を参照)。
* 可読性を高めるために、例えば以下のように、 ``{% endblock %}`` にブロッ
クの *名前* を指定できます::
{% block content %}
...
{% endblock content %}
大きなテンプレートの編集で、どこで ``{% block %}`` タグが閉じているか
探すのに便利です。
最後に、同じテンプレート中に同じ名前の :ttag:`block` を複数定義できないこ
とに注意して下さい。この制限は、ブロックタグが「双方向」に作用するため、す
なわち、あるブロックタグは何らかの値を埋めるための穴であるだけでなく、穴を
埋める *親テンプレートの* コンテンツも定義しているために存在しています。同
じ名前の :ttag:`block` が一つのテンプレート内に複数あると、そのテンプレー
トの親テンプレートは、該当するブロックの内容を子テンプレートのどの
:ttag:`block` 設定で置き換えればよいのか分からなくなってしまいます。
.. _next section: #automatic-html-escaping
.. _automatic-html-escaping:
HTML の自動エスケープ
=======================
テンプレートから HTML を生成するときには、変数内の文字が HTML のレンダリン
グ結果を壊してしまうというリスクが常に付きまといます。例えば、以下のような
テンプレートフラグメントを考えてみましょう::
こんにちは {{ name }} さん
一件、このコードはユーザ名を表示するだけの無害なものに見えますが、名前を以
下のような値にすると、何が起こるでしょう::
テンプレートは以下のようにレンダされます::
Hello,
その結果、 JavaScript の警告ボックスを表示できてしまいます!
同様に、名前に以下のようにして ``'<'`` 文字をいれると同でしょう::
..code-block::html
username
レンダ結果は以下のようになります::
Hello, username
これで、以降のWebページは全部ボールド表示になってしまいます!
言うまでもなく、ユーザが入力したデータは盲目に信頼してはならず、直接 Web ペー
ジに挿入すべきでもありません。悪意のあるユーザはこの手の穴を使って悪さをす
るものです。こうしたセキュリティホールは、
`クロスサイトスクリプティング`_ (XSS) 攻撃と呼ばれています。
クロスサイトスクリプティングを防ぐには、二つの方法があります:
* まず、信頼できない変数は全て (後述の) ``escape`` フィルタを通します。
このフィルタは危険を及ぼす可能性のある HTML 文字を無害な文字に変換し
ます。 Django では、初期の数年はこの方法をデフォルトとして採用してい
ましたが、ユーザ、すなわち開発者やテンプレートの作者に、全てをエスケー
プするよう気配りする負荷をかけるという問題がありました。
* もう一つは、自動 HTML エスケープを使うというものです。この節の後半で
は、自動エスケープのからくりについて述べています。
開発版の Django では、デフォルトの設定として、全てのテンプレートは変数タグ
を自動的にエスケープします。具体的には、以下の 5 つの文字がエスケープされます:
* ``<`` は ``"<"`` に変換されます。
* ``>`` は ``">"`` に変換されます。
* ``"'"`` (クオート) は ``'''`` に変換されます。
* ``'"'`` (二重クオート) は ``'"'`` に変換されます。
* ``"&"`` は ``"&"`` に変換されます。
この動作はデフォルトで適用されていることを強調しておきます。Django テンプレー
トシステムを使っているかぎり、エスケープに関する問題からは守られているのです。
.. _Cross Site Scripting: http://en.wikipedia.org/wiki/Cross-site_scripting
.. _`クロスサイトスクリプティング`: http://ja.wikipedia.org/wiki/クロスサイトスクリプティング
自動エスケープを切るには
---------------------------
サイト単位やテンプレート単位、変数単位でデータの自動エスケープを切るには、
いくつかの方法があります。
どんなときに、自動エスケープを切る必要があるのでしょうか。テンプレート変数
の中には、生の HTML としてレンダするように *意図された* データがあります。
そうした場合にはコンテンツがエスケープされてほしくはないでしょう。例えば、
データベースに HTML を保存していて、テンプレートに直接埋め込みたい場合を考
えてみましょう。また、 Django のテンプレートシステムを使って、 HTML *以外*
のデータ、例えば電子メールメッセージなどを生成したい場合がそうです。
変数単位の制御
~~~~~~~~~~~~~~~~
変数個々に自動エスケープを無効にするには、 :tfilter:`safe` フィルタを使います::
エスケープされる: {{ data }}
エスケープされない: {{ data|safe }}
*safe* という言葉を、 *これ以上エスケープしないよう保護(safe)する* とか、
*HTML として解釈しても安全(safe)である* という意味だと考えてください。
例えば、 ``data`` に ``''`` が入っていた場合、出力は以下のようになります::
エスケープされる: <b>
エスケープされない:
テンプレートブロック単位の制御
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
テンプレートで自動エスケープを制御するには、テンプレート (または
テンプレートの一部) を、以下のように :ttag:`autoescape` タグで囲みます::
{% autoescape off %}
こんにちは {{ name }} さん
{% endautoescape %}
:ttag:`autoescape` タグは、 ``on`` または ``off`` を引数にとります。
テンプレートのある範囲を自動エスケープして、さらにその一部で自動エスケープ
を切りたい場合には、以下のように入れ子にできます::
Auto-escaping is on by default. Hello {{ name }}
{% autoescape off %}
This will not be auto-escaped: {{ data }}.
Nor this: {{ other_data }}
{% autoescape on %}
Auto-escaping applies again: {{ name }}
{% endautoescape %}
{% endautoescape %}
自動エスケープのタグは、他のブロックタグと同様、タグを設定したテンプレート
を継承している他のテンプレートや、 ``include`` で取り込んだテンプレートでも
有効です。例えば::
# base.html
{% autoescape off %}
{% block title %}{% endblock %}
{% block content %}
{% endblock %}
{% endautoescape %}
# child.html
{% extends "base.html" %}
{% block title %}This & that{% endblock %}
{% block content %}{{ greeting }}{% endblock %}
自動エスケープがベースのテンプレートで無効化されているので、子テンプレート
でも自動エスケープは無効化されます。結果として、 ``greeting`` 変数の値が
``Hello!`` の時には以下の HTML がレンダされます::
This & that
Hello!
注意点
-------
一般に、テンプレートの作者は自動エスケープをあまり意識するべきではありませ
ん。 Python サイドの開発者 (ビューやカスタムフィルタ) の作者が、どのデータ
をエスケープすべきでないかを考え、データを適切にマークして、テンプレートに
うまく表示されるようにすべきなのです。
テンプレートを作成していて、自動エスケープが有効な環境で使われるかどうか分
からないような場合には、エスケープの必要な変数全てに ``escape`` フィルタを
追加してください。自動エスケープがオンの場合、 :tfilter:`escape` フィルタがデータ
を *二重にエスケープする* ような危険性はありません。 :tfilter:`escape` フィルタは
変数の自動エスケープには影響しないのです。
.. _string-literals-and-automatic-escaping:
文字列リテラルと自動エスケープ
-------------------------------
先に説明したように、フィルタの引数は文字列であってもかまいません::
{{ data|default:"文字列リテラルだよ" }}
文字列リテラルは、自動エスケープ **されずに** テンプレート内に挿入されます。
文字列リテラルは、 :tfilter:`safe` フィルタを通して渡されたかのように振る舞います。
このような仕様になっているのは、テンプレートの作者が文字列リテラルがどのよ
うに処理されるかを制御でき、テンプレートを書くときにテキストが正しくエスケー
プされるよう配慮できるからです。
従って、以下のようにテンプレートを書いてください::
{{ data|default:"3 < 2" }}
以下のようにはしないでください::
{{ data|default:"3 < 2" }} <-- ダメ。こんな書き方をしてはいけません
引数にリテラルを使っても、変数自体に対するエスケープの挙動には影響しません。
変数はテンプレート作者の制御の範囲外にあり、自動的にエスケープされます。
.. _template-accessing-methods:
メソッドの呼び出しにアクセスする
================================
オブジェクトに備え付けられたほとんどのメソッドの呼び出しはテンプレートの
中からでも使うことができます。これは、テンプレートがただのクラスの属性(
フィールド名のように)とビューでの変数を通したアクセス以上のものであると
いうことです。例えば、Djangoでの例ではORMは
:ref:`"entry_set"` 文法を提供していて、Foreign
キーに関係するオブジェクトの集合を見つけることができます。従って、
"comment"と呼ばれるモデルが"task"というモデルとフォーリンキーで繋がってい
るとき、ループを用いることで"task"を通して全ての"comment"オブジェクトにア
クセスすることができます。ちょうど、こんな風に。::
{% for comment in task.comment_set.all %}
{{ comment }}
{% endfor %}
似たように、 :doc:`QuerySets` は ``count()`` メソ
ッドというオブジェクトの個数を数えるために提供しています。従って、タスク
と関連する全てのコメントの個数を取得することも出来ます。::
{{ task.comment_set.all.count }}
そして、もちろん簡単にモデル自身で定義されたメソッドにもアクセスすること
ができます::
# モデル内で
class Task(models.Model):
def foo(self):
return "bar"
# テンプレート内で
{{ task.foo }}
なぜなら、Django ではテンプレートのプログラム的な使用を厳しく制限してい
て、テンプレートの中からメソッドを呼び出すことは出来ないからです。データは
ビューの中で作られ、テンプレートでは表示のためだけに使うべきだからです。
.. _loading-custom-template-libraries:
カスタムタグとカスタムフィルタのライブラリ
==========================================
アプリケーションによっては、カスタムのタグやフィルタライブラリを提供してい
ます。こうしたタグをテンプレートで使いたい場合、 :ttag:`load` タグを使い
ます::
{% load comments %}
{% comment_form for blogs.entries entry.id with is_public yes %}
上の例では、 :ttag:`load` タグは ``comments`` という名前のタグライブラリを読み
込んでいます。このタグライブラリを読み込むと、 ``comment_form`` タグを使え
るようになります。カスタムライブラリのリストを探したければ、自分のサイトの
admin でドキュメント置場を参照してください。
:ttag:`load` タグは複数のライブラリ名を同時に読み込めます。ライブラリ名は
スペースで区切って下さい::
{% load comments i18n %}
カスタムのテンプレートライブラリを作成する方法は
:doc:`/howto/custom-template-tags` を参照してください。
カスタムのライブラリとテンプレートの継承
----------------------------------------
カスタムタグやフィルタライブラリをロードした場合、タグやフィルタは現在のテ
ンプレートだけで利用でき、テンプレート継承パス上の親テンプレートや子テンプ
レートでは利用できません。
例えば、 ``foo.html`` に ``{% load comments %}`` というタグを入れておいても、
子テンプレート (``{% extends "foo.html" %}`` を使っているテンプレート) で
comments という名前のテンプレートタグやフィルタを使えるわけでは
*ありません* 。子テンプレート側で独自に ``{% load comments %}`` を入れてお
く必要があります。
これはメンテナンス性を高めるための仕様です。