{% load cms_tags sekizai_tags %}<!DOCTYPE html> <html>
<head> {% render_blocks “css” %} </head>
<body> {% cms_toolbar %}
{% placeholder “main” %}
{% render_blocks “js” %} </body>
</html>
テンプレートはテキストファイルで構成されます。 テンプレートには、テンプレートを処理する際に実際の値に置き換えられる 変数 (variable) と、テンプレート上でロジックを制御する タグ (tag) が含まれます。
次に示すのは、基本的な項目をいくつか組み込んだ最小限のテンプレートです。 各項目についてはこのドキュメントの後の部分で詳しく説明します:
{% extends "base_generic.html" %}
{% block title %}{{ section.title }}{% endblock %}
{% block content %}
<h1>{{ section.title }}</h1>
{% for story in story_list %}
<h2>
<a href="{{ story.get_absolute_url }}">
{{ story.headline|upper }}
</a>
</h2>
<p>{{ story.tease|truncatewords:"100" }}</p>
{% endfor %}
{% endblock %}
変数 (variable) は {{ variable }}
の形式をとります。テンプレート
エンジンが変数名を見つけると、変数を評価して値に置き換えたものを出力します。
変数名は英字と数字とアンダースコア(_
)の組み合わせです。
変数名にスペース、句読点を含めないでください。
また、ドット(.
)は変数の中に出現し、変数の属性値にアクセスするために使います。
上の例では、 {{ section.title }}
は section
オブジェクトの
title
属性に置き換えられます。
実在しない変数を使うと ''
(空文字列)に置換されます。
表示する変数に手を加えたい場合には フィルタ (filter) を使います。
フィルタは {{ name|lower }}
の形式をとります。この例では、変数 {{
name }}
の値は lower
フィルタ、すなわち文字を小文字に変換するフィルタ
を適用してから表示されます。フィルタの適用は (|
) で表現します。
フィルタは「連鎖 (chain)」できます。フィルタを連鎖させると、あるフィルタか
らの出力を別のフィルタに渡せます。例えば、 {{ text|escape|linebreaks }}
は、テキストの内容をエスケープして、改行を <p>
タグに置き換える時に使われます。
フィルタによっては引数をとります。フィルタの引数は
{{ bio|truncatewords:"30" }}
の形式をとります。
この例では、変数 bio
の最初の 30 語を表示します。
フィルタの引数にスペースが入っている場合は、二重引用符で囲ってください。例
えば、カンマとスペースでリストを結合するには {{ list|join:", " }}
のようにします。
利用可能なフィルタ一覧 で、 JSM7で使用可能なフィルタを説明していますが、ここでいくつか例を示します。
default
入力が空や False
の場合、引数に指定したデフォルト値を使いま
す。そうでなければ、入力をそのまま使います
使用例:
{{ value|default:"nothing" }}
value
が存在しなかったり空だったりすると、 “nothing
” を出力
します。
length
入力値の長さを返します。文字列とリストいずれにも作用します。
使用例:
{{ value|length }}
value
が ['a', 'b', 'c', 'd']
なら、 4
を出力します。
striptags
[X]HTML タグを全てはぎとります。
使用例:
{{ value|striptags }}
value
が
"<b>Joel</b> <button>is</button> a <span>slug</span>"
なら、 "Joel is a slug"
を出力します。
タグは {% tag %}
の形式をとり、以下の種類があります。
タグによっては、開始タグと終了タグ
({% tag %} ... tag contents ... {% endtag %}
) を必要とするものがあります。
利用可能なタグ一覧 で JSM7で使用可能なフィルタを説明していますが、ここでいくつか例を示します。
load
JSM7で必要なテンプレートタグリストを読み込みます。 最上位のテンプレート(例えば、base.html)の先頭には次のタグを必ず記述してください。 これらのタグは 必須 です:
{% load cms_tags, menu_tags, sekizai_tags %}
for
アレイの各要素に渡ってループします。例えば、アスリート (athlete) の
リストを athlete_list
で渡して表示するには、以下のようにします:
<ul>
{% for athlete in athlete_list %}
<li>{{ athlete.name }}</li>
{% endfor %}
</ul>
if
/ else
変数を評価して、値が「真」 (値が存在して、空の配列でなく、ブール値 が偽でない) の場合、ブロック内のコンテンツを出力します:
{% if athlete_list %}
Number of athletes: {{ athlete_list|length }}
{% else %}
No athletes.
{% endif %}
上の例では、 athlete_list
が空でなければ、アスリートの人数を
{{ athlete_list|length }}
で表示します。
if
タグの中で、他のフィルターや変数を使うにはを使うこともできます:
{% if athlete_list|length > 1 %}
Team: {% for athlete in athlete_list %} ... {% endfor %}
{% else %}
Athlete: {{ athlete_list.0.name }}
{% endif %}
テンプレート中で行内の一部をコメントアウトするには、コメント構文 {# #}
を使います。
例えば、以下のテンプレートをレンダリングすると 'hello'
になります:
{# greeting #}hello
コメント内には任意のテンプレートコードを入れられます。コメント内の テンプレートコードが無効なものであってもエラーにはなりません(評価されません):
{# {% if foo %}bar{% else %} #}
複数行をコメントアウトしたければ、 comment
タグを使います。
{% comment %}
から {% endcomment %}
までの内容が全て無視されます。
テンプレートの継承 (inheritance) は、 サイト内で共通に使われる要素が入ったベースとなる「骨組み」テンプレートを作り、 そのテンプレートを子テンプレートで上書き(オーバーライド)する仕組みです。 ブロック(block) を使用します。
テンプレートの継承を理解するための例を示します:
<!DOCTYPE html>
<html lang="ja">
<head>
<link rel="stylesheet" href="style.css" />
<title>{% block title %}My amazing site{% endblock %}</title>
</head>
<body>
<div id="sidebar">
{% block sidebar %}
<ul>
<li><a href="/">Home</a></li>
<li><a href="/blog/">Blog</a></li>
</ul>
{% endblock %}
</div>
<div id="content">
{% block content %}{% endblock %}
</div>
</body>
</html>
このテンプレートは、単純な 2 カラム形式のページで使うような HTML のスケルト
ンドキュメントです。これを base.html
と呼びます。
空のブロック( {% block content %}{% endblock %}
)をコンテンツで
埋めるのは子テンプレートの仕事です。
この例は、 block
タグを使って 3 つのブロックを定義し、その箇所に子テンプ
レートが値を埋められるようにしています。 block
タグの役割は、テンプレー
ト中のタグで囲まれた部分を子テンプレートでオーバライドできることをテンプレー
トエンジンに知らせることです。
子テンプレートは以下のようになります:
{% extends "base.html" %}
{% block title %}My amazing blog{% endblock %}
{% block content %}
{% for entry in blog_entries %}
<h2>{{ entry.title }}</h2>
<p>{{ entry.body }}</p>
{% endfor %}
{% endblock %}
最上部の extends
タグが継承を示します。このタグはテンプレートエンジンに対
して、自分自身が他のテンプレートを拡張 (extend) していることを教えます。
テンプレートシステムがこのテンプレートを処理する際、システムはまず親となるテ
ンプレート – ここでは “base.html” を探します。
この時点で、テンプレートエンジンは base.html
内に三箇所の
block
が定義されていることに気づき、これらのブロックを子テンプレー
トの該当するブロックで置き換えます。 blog_entries
の値に応じて、出力は
以下のようになります:
<!DOCTYPE html>
<html lang="ja">
<head>
<link rel="stylesheet" href="style.css" />
<title>My amazing blog</title>
</head>
<body>
<div id="sidebar">
<ul>
<li><a href="/">Home</a></li>
<li><a href="/blog/">Blog</a></li>
</ul>
</div>
<div id="content">
<h2>Entry one</h2>
<p>This is my first entry.</p>
<h2>Entry two</h2>
<p>This is my second entry.</p>
</div>
</body>
</html>
子テンプレートには sidebar
ブロックが定義されていないので、親テンプレー
トの値がそのまま使われます。親テンプレートの {% block %}
タグの内容は、
常にフォールバックの値として使われます。
テンプレートの継承は必要に応じて何段階にもできます。継承を使うよくある場合 の一つに、以下のような三段階のアプローチがあります:
base.html
テンプレートを作成します。base_SECTIONNAME.html
テンプレート
を作成します。例えば、 base_news.html
, base_sports.html
と
いった具合です。これらのテンプレートでは base.html
を拡張して、セ
クション固有のスタイルやデザインを取り込みます。このようなアプローチを取れば、コードの再利用性を最大限に高め、セクション毎 のナビゲーションのような項目を簡単に共通のコンテンツ領域に追加できます。
テンプレート継承を使うときの注意点をいくつか挙げます:
{% extends %}
はテンプレート中の最初のタグにしてください。
ベースのテンプレートで {% block %}
を多用すればするほど、よりよい
テンプレートになります。子テンプレートは親テンプレートのブロックを必
ずしも全て定義する必要はありません。ベーステンプレートまたは親テンプレートで
ブロックをたくさん用意して、適切なデフォルト値を入れておいて、子テンプレートで必
要な値だけを再定義すればよいです。
同じような内容を含むテンプレートをいくつも作っていることに気づいたら、
それは、その内容を親テンプレートの {% block %}
に入れるべきです。
親テンプレートのブロックに入っているコンテンツを取り出す必要がある場
合、 {{ block.super }}
とするとうまくいきます。親テンプレートのブ
ロックをオーバライドするのではなく、内容を追加したい場合に便利です。
{{ block.super }}
で挿入されたデータは、通常、親テンプレートで
既にエスケープされているので、自動的にエスケープされません
(HTML の自動エスケープ を参照)。
可読性を高めるために、例えば以下のように、 {% endblock %}
にブロッ
クの 名前 を指定できます:
{% block content %}
...
{% endblock content %}
大きなテンプレートの編集で、どこで {% block %}
タグが閉じているか
探すのに便利です。
同じテンプレート中に同じ名前の block
を複数定義できません。
JSM7では、テンプレートの変数タグを自動的にエスケープします。 具体的には、以下の 5 つの文字がエスケープされます:
<
は "<"
に変換されます。>
は ">"
に変換されます。"'"
(クオート) は '''
に変換されます。'"'
(二重クオート) は '"'
に変換されます。"&"
は "&"
に変換されます。サイト単位やテンプレート単位、変数単位でデータの自動エスケープを切るにはいくつかの方法があります。
変数個々に自動エスケープを無効にするには、 safe
フィルタを使います:
エスケープされる: {{ data }}
エスケープされない: {{ data|safe }}
例えば、 data
に '<b>'
が入っていた場合、出力は以下のようになります:
エスケープされる: <b>
エスケープされない: <b>
ブロック単位で自動エスケープを制御するには、テンプレート (または
テンプレートの一部) を、以下のように autoescape
タグで囲みます:
{% autoescape off %}
こんにちは {{ name }} さん
{% endautoescape %}
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 %}
<h1>{% block title %}{% endblock %}</h1>
{% block content %}
{% endblock %}
{% endautoescape %}
# child.html
{% extends "base.html" %}
{% block title %}This & that{% endblock %}
{% block content %}{{ greeting }}{% endblock %}
自動エスケープがベースのテンプレートで無効化されているので、子テンプレート
でも自動エスケープは無効化されます。結果として、 greeting
変数の値が
<b>Hello!</b>
の時には以下の HTML がレンダリングされます:
<h1>This & that</h1>
<b>Hello!</b>
テンプレートを作成していて、自動エスケープが有効な環境で使われるかどうか分
からないような場合には、エスケープの必要な変数全てに escape
フィルタを
追加してください。自動エスケープがオンの場合、 escape
フィルタがデータ
を 二重にエスケープする ような危険性はありません。 escape
フィルタは
変数の自動エスケープに影響しません。
先に説明したように、フィルタの引数は文字列であってもかまいません:
{{ data|default:"文字列リテラルです" }}
文字列リテラルは、自動エスケープ されずに テンプレート内に挿入されます。
文字列リテラルは、 safe
フィルタを通して渡されたかのように振る舞います。
このような仕様になっているのは、テンプレートの作者が文字列リテラルがどのよ
うに処理されるかを制御でき、テンプレートを書くときにテキストが正しくエスケー
プされるよう配慮できるためです。
従って、以下のようにテンプレートを書いてください:
{{ data|default:"3 < 2" }}
以下のようにはしないでください:
{{ data|default:"3 < 2" }} <-- NG
引数にリテラルを使っても、変数自体に対するエスケープの挙動には影響しません。 変数はテンプレート作者の制御の範囲外にあり、自動的にエスケープされます。