Python プログラマーのための Django テンプレート言語¶
この文書は Django テンプレートシステムがどのように動作し、どのように拡張するか、技術的な観点から説明します。構文に関するリファレンスを探しているなら、 Django テンプレート言語 を参照してください。
テンプレート、 コンテキスト、変数、タグ、レンダリングについての理解を前提としています。これらの概念に馴染みがなければ、 Django テンプレート言語入門 からスタートしてください。
概要¶
Pythonでテンプレートシステムを使うには3つのステップがあります:
これらの各ステップで、Django プロジェクトは通常、テンプレートシステムの低レベルの API ではなく、 バックエンドに依存しない高レベルの API に依存しています:
TEMPLATES設定の中で、各DjangoTemplatesバックエンドに対して、DjangoはEngineをインスタンス化します。DjangoTemplatesはEngineをラップし、共通のテンプレートバックエンドAPIに適応させます。django.template.loaderモジュールはテンプレートを読み込むためのget_template()のなどの関数を提供します。これらは実際のdjango.template.Templateをラップしたdjango.template.backends.django.Templateを返します。前のステップで取得した
Templateにはrender()メソッドがあり、コンテキストと場合によってはリクエストをContextに集約し、その下にあるTemplateにレンダリングを委譲します。
エンジンを設定する¶
もし DjangoTemplates バックエンドを使っているのであれば、これはおそらくあなたが探しているドキュメントではありません。後述する Engine クラスのインスタンスには、そのバックエンドの engine 属性を使ってアクセスすることができ、後述する属性のデフォルトは DjangoTemplates で渡されたもので上書きされます。
- class Engine(dirs=None, app_dirs=False, context_processors=None, debug=False, loaders=None, string_if_invalid='', file_charset='utf-8', libraries=None, builtins=None, autoescape=True)[ソース]¶
Engineをインスタンス化する際は、すべての引数をキーワード引数として渡す必要があります:dirsはエンジンがテンプレートのソースファイルを探すディレクトリのリストです。これはfilesystem.Loaderを設定するために使用されます。デフォルトは空のリストです。
app_dirsはloadersのデフォルト値にだけ影響します。下記を参照してください。デフォルトは
Falseです。autoescapeはHTMLのオートエスケープを有効にするかどうかをコントロールします。デフォルトは
Trueです。警告
HTML以外のテンプレートをレンダリングする場合のみ
Falseに設定してください!'context_processors'は、リクエストでテンプレートがレンダリングされるときにコンテキストを生成するために使用される呼び出し可能オブジェクトへの Python のドット区切りパスのリストです。これらの呼び出し可能オブジェクトはリクエストオブジェクトを引数として取り、コンテキストにマージされるアイテムのdictを返します。デフォルトは空のリストです。
詳しくは
RequestContextを参照してください。debugはテンプレートのデバッグモードのオン/オフを切り替える真偽値です。もしTrueなら、テンプレートエンジンは追加のデバッグ情報を保存し、テンプレートのレンダリング中に例外が発生した場合に詳細なレポートを表示できます。デフォルトは
Falseです。loadersはテンプレートローダクラスのリストで、文字列で指定します。各Loaderクラスは特定のソースからテンプレートをインポートする方法を知っています。任意で、文字列の代わりにタプルを使うこともできます。タプルの最初の項目はLoaderクラス名で、それ以降の項目は初期化時にLoaderに渡されます。リストにはデフォルトでは下記が含まれます:
'django.template.loaders.filesystem.Loader''django.template.loaders.app_directories.Loader'、これが含まれるのはapp_dirsがTrueの場合だけです。
これらのローダーは
django.template.loaders.cached.Loaderでラップされます。詳しくは ローダーの種類 を参照してください。
'string_if_invalid'は、無効な(例えばスペルミスのある)変数に対してテンプレートシステムが使用する文字列です。デフォルトは空文字列です。
詳しくは 無効な変数の扱い を参照してください。
'file_charset'は、ディスク上のテンプレートファイルを読み込む際に使用する文字セットです。デフォルトは
'utf-8'です。'libraries': テンプレートエンジンに登録するテンプレートタグモジュールのラベルとドット区切りPythonパスの辞書。これは新しいライブラリを追加したり、既存のライブラリの代替ラベルを提供するために使用します。たとえば下記のように:Engine( libraries={ "myapp_tags": "path.to.myapp.tags", "admin.urls": "django.contrib.admin.templatetags.admin_urls", }, )
{% load %}タグに対応する辞書のキーを渡すことでライブラリをロードできます。'builtins': ビルトイン に追加するテンプレートタグモジュールのドット区切りPythonパスのリストです。たとえば:Engine( builtins=["myapp.builtins"], )
{% load %}タグを呼び出さなくても、組み込みライブラリのタグやフィルタを使うことができます。
- static Engine.get_default()[ソース]¶
最初に設定された
DjangoTemplatesエンジンからEngineを返します。エンジンが設定されていない場合、ImproperlyConfiguredを発生させます。これは、グローバルに利用可能で、暗黙的に設定されたエンジンに依存するAPIを保持するために必要です。それ以外の使用は強く推奨されません。
- Engine.select_template(template_name_list)[ソース]¶
get_template()と同様ですが、名前のリストを受け取り、最初に見つかったテンプレートを返します。
テンプレートを読み込む¶
Template を作成する推奨される方法は Engine のファクトリーメソッドを呼び出すことです。これは get_template(), select_template(), from_string() を指します。
TEMPLATES 設定で DjangoTemplates エンジンが定義されている Django プロジェクトでは、 Template を直接インスタンス化できます。複数の DjangoTemplates エンジンが定義されている場合、最初のものが使用されます。
- class Template[ソース]¶
このクラスは
django.template.Templateにあります。コンストラクタは1つの引数(生のテンプレートコード)を取ります:from django.template import Template template = Template("My name is {{ my_name }}.")
背景
システムは生のテンプレートコードを一度だけ解析します。 Template オブジェクトを作成するときです。それ以降は、パフォーマンスのために内部的にツリー構造として保存されます。
構文解析自体も非常に高速です。構文解析のほとんどは、1つの短い正規表現を呼び出すだけで行われます。
コンテキストをレンダリングする¶
一度コンパイルされた Template オブジェクトがあれば、それを使ってコンテキストをレンダリングできます。同じテンプレートを再利用して、異なるコンテキストで何度でもレンダリングできます。
- class Context(dict_=None, autoescape=True, use_l10n=None, use_tz=None)[ソース]¶
django.template.Contextのコンストラクタは、オプションの引数(変数名と変数の値をマッピングした辞書)を取ります。3つのオプションのキーワード引数も指定できます:
autoescapeはHTMLのオートエスケープを有効にするかどうかをコントロールします。デフォルトは
Trueです。警告
HTML以外のテンプレートをレンダリングする場合のみ
Falseに設定してください!use_l10nは、値がデフォルトでローカライズされるかどうかを上書きします。Trueに設定すると、数値や日付はロケールに基づいてフォーマットされます。デフォルトは
Noneです。詳細は テンプレート内でローカライズをコントロールする を参照してください。
use_tzは、日付がテンプレートで表示される際にローカル時間に変換されるかどうかを上書きします。Trueに設定すると、すべての日付がローカルタイムゾーンを使用して表示されます。これはUSE_TZよりも優先されます。デフォルトは
Noneです。詳細は テンプレートでのタイムゾーン aware な出力 を参照してください。
使用例については、下記の Context オブジェクトを使って遊ぶ を参照してください。
- Template.render(context)[ソース]¶
Contextを指定してTemplateオブジェクトのrender()メソッドを呼び出します:>>> from django.template import Context, Template >>> template = Template("My name is {{ my_name }}.") >>> context = Context({"my_name": "Adrian"}) >>> template.render(context) "My name is Adrian." >>> context = Context({"my_name": "Dolores"}) >>> template.render(context) "My name is Dolores."
変数とルックアップ¶
変数名はアルファベット(A-Z)、数字(0-9)、アンダースコア(ただしアンダースコアで始まってはならない)、ドットで構成されていなければなりません。
ドットはテンプレートレンダリングにおいて特別な意味を持ちます。変数名のドットは ルックアップ を意味します。具体的には、テンプレートシステムが変数名でドットを見つけると、以下の順番でルックアップを試みます:
辞書のルックアップ。例:
foo["bar"]属性のルックアップ。例:
foo.barリストインデックスのルックアップ。例:
foo[bar]
テンプレートコンテキストに変数 "bar "が存在する場合、{{ foo.bar }} のようなテンプレート式中の "bar "はリテラル文字列として解釈され、変数 "bar" の値は使用されないことに注意してください。
テンプレートシステムは、最初に機能するルックアップ・タイプを使用します。これは短絡ロジックです。以下はその例です:
>>> from django.template import Context, Template
>>> t = Template("My name is {{ person.first_name }}.")
>>> d = {"person": {"first_name": "Joe", "last_name": "Johnson"}}
>>> t.render(Context(d))
"My name is Joe."
>>> class PersonClass:
... pass
...
>>> p = PersonClass()
>>> p.first_name = "Ron"
>>> p.last_name = "Nasty"
>>> t.render(Context({"person": p}))
"My name is Ron."
>>> t = Template("The first stooge in the list is {{ stooges.0 }}.")
>>> c = Context({"stooges": ["Larry", "Curly", "Moe"]})
>>> t.render(c)
"The first stooge in the list is Larry."
もし変数のどれかが呼び出し可能オブジェクトであれば、テンプレートシステムは呼び出しを試みます。例:
>>> class PersonClass2:
... def name(self):
... return "Samantha"
...
>>> t = Template("My name is {{ person.name }}.")
>>> t.render(Context({"person": PersonClass2}))
"My name is Samantha."
呼び出し可能な変数は、単純なルックアップしか必要としない変数よりも少し複雑です。以下に注意すべき点を示します:
この変数が呼び出されたときに例外が発生した場合、例外が
silent_variable_failure属性の値がTrueでない限り、例外は伝播します。例外にsilent_variable_failure属性があり、その値がTrueである場合、その変数はエンジンのstring_if_invalid設定オプションの値(デフォルトでは空文字列)としてレンダリングされます。例:>>> t = Template("My name is {{ person.first_name }}.") >>> class PersonClass3: ... def first_name(self): ... raise AssertionError("foo") ... >>> p = PersonClass3() >>> t.render(Context({"person": p})) Traceback (most recent call last): ... AssertionError: foo >>> class SilentAssertionError(Exception): ... silent_variable_failure = True ... >>> class PersonClass4: ... def first_name(self): ... raise SilentAssertionError ... >>> p = PersonClass4() >>> t.render(Context({"person": p})) "My name is ."
django.core.exceptions.ObjectDoesNotExistはすべての Django データベース API のDoesNotExist例外用の基本クラスですが、silent_variable_failure = Trueを持っていることに注意してください。そのため、 Django モデルオブジェクトで Django テンプレートを使っている場合、DoesNotExist例外はすべてサイレントエラーになります。変数は必要な引数がない場合のみ呼び出すことができます。そうでない場合、システムはエンジンの
string_if_invalidオプションの値を返します。
いくつかの変数を呼び出すときに副作用が発生する可能性があり、テンプレートシステムがそれらにアクセスできるようにするのは愚策またはセキュリティホールと言えます。
良い例が、各 Django モデルオブジェクトの
delete()メソッドです。テンプレートシステムはこのようなことをしてはいけません:I will now delete this valuable data. {{ data.delete }}
To prevent this, set an
alters_dataattribute on the callable variable. The template system won't call a variable if it hasalters_data=Trueset, and will instead replace the variable withstring_if_invalid, unconditionally. The dynamically-generateddelete()andsave()methods on Django model objects getalters_data=Trueautomatically. Example:def sensitive_function(self): self.database_record.delete() sensitive_function.alters_data = True
Occasionally you may want to turn off this feature for other reasons, and tell the template system to leave a variable uncalled no matter what. To do so, set a
do_not_call_in_templatesattribute on the callable with the valueTrue. The template system then will act as if your variable is not callable (allowing you to access attributes of the callable, for example).
無効な変数の扱い¶
通常、変数が存在しない場合、テンプレートシステムはエンジンの string_if_invalid 設定オプションの値を挿入します。
string_if_invalid が '' (空文字列) に設定されている場合のみ、無効な変数に適用されるフィルタが適用されます。もし string_if_invalid が他の値に設定されている場合、変数フィルタは無視されます。
この動作は if, for, regroup のテンプレートタグでは少し異なります。これらのテンプレートタグに無効な変数が指定された場合、その変数は None として解釈されます。これらのテンプレートタグ内の無効な変数には常にフィルタが適用されます。
もし string_if_invalid が '%s' を含む場合、フォーマットマーカーは無効な変数名に置き換えられます。
デバッグ専用です!
string_if_invalid は便利なデバッグツールですが、「開発のデフォルト」としてオンにするのはよくありません。
Django 組み込みのものを含む多くのテンプレートは、存在しない変数に遭遇した場合、テ ンプレートシステムの沈黙に依存しています。もし string_if_invalid に '' 以外の値を代入すると、これらのテンプレートやサイトでレンダリングの問題が発生します。
通常、string_if_invalid は特定のテンプレートの問題をデバッグするためだけに有効にし、デバッグが完了したらオフにすべきです。
組み込み変数¶
すべてのコンテキストは True, False, None を含みます。ご想像の通り、これらの変数は対応する Python オブジェクトに解決されます。
文字列リテラルの制約¶
Django のテンプレート言語には、独自の構文に使われる文字をエスケープする手段がありません。例えば、 {% や %} のような文字列を出力する必要がある場合は、 templatetag タグが必要です。
これらのシーケンスをテンプレートフィルタやタグの引数に含めたい場合にも、同じような問題があります。例えば、ブロックタグを解析するとき、 Django のテンプレートパーサは {% の後に %} が最初に現れるかどうかを調べます。これは "%}" が文字列リテラルとして使われるのを阻止します。たとえば、以下のような式では TemplateSyntaxError が発生します:
{% include "template.html" tvar="Some string literal with %} in it." %}
{% with tvar="Some string literal with %} in it." %}{% endwith %}
フィルタの引数に予約済みのシーケンスを使用すると、同じ問題が発生することがあります:
{{ some.variable|default:"}}" }}
これらのシーケンスで文字列を使用する必要がある場合は、テンプレート変数に格納するか、カスタムテンプレートタグまたはフィルタを使用して制限を回避してください。
Context オブジェクトを使って遊ぶ¶
たいていの場合、Context() に辞書を渡して Context オブジェクトをインスタンス化します。しかし、一度インスタンス化された Context オブジェクトに対しても、標準的な辞書構文を使ってアイテムの追加や削除を行うことができます:
>>> from django.template import Context
>>> c = Context({"foo": "bar"})
>>> c["foo"]
'bar'
>>> del c["foo"]
>>> c["foo"]
Traceback (most recent call last):
...
KeyError: 'foo'
>>> c["newvariable"] = "hello"
>>> c["newvariable"]
'hello'
- Context.get(key, otherwise=None)¶
もし
keyがコンテキストに存在すればkeyの値を返し、そうでなければotherwiseを返します。
- Context.setdefault(key, default=None)¶
もし
keyがコンテキスト内にあれば、その値を返します。そうでない場合は、defaultの値を持つkeyを挿入し、defaultを返します。
- Context.pop()¶
- Context.push()¶
コンテキストオブジェクトはスタックです。つまり、 push() したり pop() したりすることができます。 pop() しすぎると django.template.ContextPopException が発生します:
>>> c = Context()
>>> c["foo"] = "first level"
>>> c.push()
{}
>>> c["foo"] = "second level"
>>> c["foo"]
'second level'
>>> c.pop()
{'foo': 'second level'}
>>> c["foo"]
'first level'
>>> c["foo"] = "overwritten"
>>> c["foo"]
'overwritten'
>>> c.pop()
Traceback (most recent call last):
...
ContextPopException
また、コンテキストマネージャとして push() を使うことで、それに対応する pop() が呼び出されるようにすることもできます。
>>> c = Context()
>>> c["foo"] = "first level"
>>> with c.push():
... c["foo"] = "second level"
... c["foo"]
...
'second level'
>>> c["foo"]
'first level'
push() に渡されたすべての引数は、新しいコンテキストレベルを構築するために使用される dict コンストラクタに渡されます。
>>> c = Context()
>>> c["foo"] = "first level"
>>> with c.push(foo="second level"):
... c["foo"]
...
'second level'
>>> c["foo"]
'first level'
push() と pop() に加えて、 Context オブジェクトは update() メソッドも定義しています。これは push() と同じように動作しますが、辞書を引数として受け取り、空の辞書の代わりにその辞書をスタックにプッシュします。
>>> c = Context()
>>> c["foo"] = "first level"
>>> c.update({"foo": "updated"})
{'foo': 'updated'}
>>> c["foo"]
'updated'
>>> c.pop()
{'foo': 'updated'}
>>> c["foo"]
'first level'
push() と同様に、コンテキストマネージャとして update() を使うことで、それに対応する pop() が呼び出されるようにすることができます。
>>> c = Context()
>>> c["foo"] = "first level"
>>> with c.update({"foo": "second level"}):
... c["foo"]
...
'second level'
>>> c["foo"]
'first level'
スタックとして Context を使うと、 いくつかのテンプレートタグ で便利です。
- Context.flatten()¶
flatten() メソッドを使うと、組み込み変数を含む Context スタック全体を一つの辞書として取得できます。
>>> c = Context()
>>> c["foo"] = "first level"
>>> c.update({"bar": "second level"})
{'bar': 'second level'}
>>> c.flatten()
{'True': True, 'None': None, 'foo': 'first level', 'False': False, 'bar': 'second level'}
内部的には flatten() メソッドは Context オブジェクトを比較できるようにするためにも使われています。
>>> c1 = Context()
>>> c1["foo"] = "first level"
>>> c1["bar"] = "second level"
>>> c2 = Context()
>>> c2.update({"bar": "second level", "foo": "first level"})
{'foo': 'first level', 'bar': 'second level'}
>>> c1 == c2
True
flatten() の結果は、ユニットテストで Context と dict を比較するのに便利です:
class ContextTest(unittest.TestCase):
def test_against_dictionary(self):
c1 = Context()
c1["update"] = "value"
self.assertEqual(
c1.flatten(),
{
"True": True,
"None": None,
"False": False,
"update": "value",
},
)
RequestContext を使う¶
- class RequestContext(request, dict_=None, processors=None, use_l10n=None, use_tz=None, autoescape=True)[ソース]¶
Django には特別な Context クラスである django.template.RequestContext があり、通常の django.template.Context とは少し異なります。最初の違いは、 HttpRequest を最初の引数として取ることです。たとえば次のようになります。
c = RequestContext(
request,
{
"foo": "bar",
},
)
2 つめの違いは、エンジンの context_processors 設定オプションによって、昆的に自動的にいくつかの変数をセットすることです。
context_processors オプションは callable -- context processors と呼ばれます -- のリストで、引数としてリクエストオブジェクトを受け取り、コンテキストに統合する項目のディクショナリを返します。 デフォルトで生成される設定ファイルでは、テンプレートエンジンは以下のコンテキストプロセッサを含んでいます:
[
"django.template.context_processors.request",
"django.contrib.auth.context_processors.auth",
"django.contrib.messages.context_processors.messages",
]
In addition to these, RequestContext always enables
'django.template.context_processors.csrf'. This is a security related
context processor required by the admin and other contrib apps, and, in case
of accidental misconfiguration, it is deliberately hardcoded in and cannot be
turned off in the context_processors option.
各プロセッサは順番通りに適用されます。したがって、1 番目と 2 番目のプロセッサがそれぞれ同じ名前の変数をコンテキストに追加したとき、2 番目の変数が 1 番目をオーバーライドします。デフォルトのプロセッサは以下で説明します。
コンテキストプロセッサが適用されたとき
コンテキストプロセッサは、コンテキストデータのトップに適用されます。これは、Context や RequestContext に与えた変数を、コンテキストプロセッサが上書きすることを意味します。コンテキストプロセッサによって提供される変数と、名前が重複しないように気をつけてください。
コンテキストデータをコンテキストプロセッサに優先させたい場合、以下のパターンを使ってください:
from django.template import RequestContext
request_context = RequestContext(request)
request_context.push({"my_name": "Adrian"})
Django はこれを使って、render() や TemplateResponse といった API で、コンテキストデータがコンテキストプロセッサをオーバーライドできるようにします。
また、省略可能な第 3 引数 processors を使って、RequestContext に追加的なプロセッサを渡すこともできます。以下の例では、RequestContext のインスタンスは ip_address 変数を格納します:
from django.http import HttpResponse
from django.template import RequestContext, Template
def ip_address_processor(request):
return {"ip_address": request.META["REMOTE_ADDR"]}
def client_ip_view(request):
template = Template("{{ title }}: {{ ip_address }}")
context = RequestContext(
request,
{
"title": "Your IP Address",
},
[ip_address_processor],
)
return HttpResponse(template.render(context))
ビルトインのテンプレートコンテキストプロセッサ¶
以下は、それぞれのビルトインのプロセッサが行うことです:
django.contrib.auth.context_processors.auth¶
このプロセッサが有効な場合、全ての RequestContext は以下の変数を含みます:
user--auth.Userのインスタンスで、現在ログイン中のユーザ (あるいはログインしていない場合はAnonymousUserのインスタンス) を表します。perms--django.contrib.auth.context_processors.PermWrapperのインスタンスで、現在ログイン中のユーザが有するパーミッションを表します。
django.template.context_processors.debug¶
このプロセッサが有効な場合、全ての RequestContext は以下の 2 つの変数を含みます -- ただし、 DEBUG 設定が True でリクエストの IP アドレス (request.META['REMOTE_ADDR']) が INTERNAL_IPS 設定内にある場合のみです:
debug--Trueです。DEBUGモードかどうかをテストするためにテンプレート内で使うことができます。sql_queries--{'sql': ..., 'time': ...}ディクショナリのリストで、リクエスト中に発生した全ての SQL クエリとかかった時間を表します。リストはデータベースエイリアス順、クエリ順です。アクセス上でレイジーに生成されます。
django.template.context_processors.i18n¶
このプロセッサが有効な場合、全ての RequestContext は以下の変数を含みます:
LANGUAGES--LANGUAGES設定の値です。LANGUAGE_BIDI-- 現在の言語がヘブライ語やアラビア語などの右から左へ書く言語の場合、Trueを返します。英語、フランス語、ドイツ語などの左から右へ書く言語の場合はFalseです。LANGUAGE_CODE-- 存在する場合はrequest.LANGUAGE_CODEで、それ以外の場合はLANGUAGE_CODE設定です。
同じ値を生成するテンプレートタグについては i18n テンプレートタグ を参照してください。
django.template.context_processors.media¶
このプロセッサが有効な場合、全ての RequestContext は変数 MEDIA_URL を含みます。これは、 MEDIA_URL 設定の値を提供します。
django.template.context_processors.static¶
このプロセッサが有効な場合、全ての RequestContext は変数 STATIC_URL を含みます。これは、STATIC_URL 設定の値を提供します。
django.template.context_processors.csrf¶
このプロセッサは、 クロスサイトリクエストフォージェリ (CSRF) 対策のための csrf_token テンプレートタグが必要とするトークンを追加します。
django.template.context_processors.csp¶
If this processor is enabled, every RequestContext will contain a variable
csp_nonce, providing a securely generated, request-specific nonce suitable
for use under a Content Security Policy. See CSP nonce usage
for details.
django.template.context_processors.request¶
このプロセッサが有効な場合、全ての RequestContext は変数``request`` を含みます。これは現在の HttpRequest です。
django.template.context_processors.tz¶
このプロセッサが有効な場合、全ての RequestContext は変数 TIME_ZONE を含みます。これは、現在アクティブなタイムゾーンの名前を提供します。
django.contrib.messages.context_processors.messages¶
このプロセッサが有効な場合、全ての RequestContext は以下の 2 つの変数を含みます:
messages-- メッセージフレームワーク を通じてセットされた、(文字列としての) メッセージのリストです。DEFAULT_MESSAGE_LEVELS-- 数値 のメッセージレベル名のマッピングです。
独自のコンテキストプロセッサを記述する¶
コンテキストプロセッサはシンプルなインタフェースを持っています。これは Python の関数で、 HttpRequest オブジェクトを引数に取り、テンプレートコンテキストに追加される辞書を返します。
たとえば、すべてのコンテキストに DEFAULT_FROM_EMAIL 設定を追加するには以下のようにします:
from django.conf import settings
def from_email(request):
return {
"DEFAULT_FROM_EMAIL": settings.DEFAULT_FROM_EMAIL,
}
カスタムコンテキストプロセッサはコードベースのどこにあっても構いません。Django が気にするのは、カスタムコンテキストプロセッサが TEMPLATES 設定の 'context_processors' オプションで指されているかどうか、直接使っている場合は Engine の context_processors 引数で指されているかどうかだけです。
テンプレートを読み込む¶
通常、テンプレートは低レベルの Template API を使うのではなく、ファイルシステム上のファイルに保存します。テンプレートは テンプレートディレクトリ として指定したディレクトリに保存します。
Django はテンプレート読み込みの設定によって、様々な場所でテンプレートディレクトリを探しますが (後述の 「ローダの種類」を参照してください)、テンプレートディレクトリを指定する最も基本的な方法は DIRS オプションを使うことです。
DIRS オプション¶
設定ファイルの TEMPLATES 設定にある DIRS オプション、または Engine の dirs 引数を使って、テンプレートディレクトリを Django に教えてください。これはテンプレートディレクトリへのフルパスを含む文字列のリストに設定する必要があります:
TEMPLATES = [
{
"BACKEND": "django.template.backends.django.DjangoTemplates",
"DIRS": [
"/home/html/templates/lawrence.com",
"/home/html/templates/default",
],
},
]
ディレクトリとテンプレートがWebサーバーによって読み取れる限り、テンプレートはどこに置いても構いません。テンプレートの拡張子は .html や .txt など好きなものを使うことができます。
これらのパスは、Windows でも Unix スタイルのスラッシュ (/) を使う必要があります。
ローダーの種類¶
デフォルトでは、 Django はファイルシステムベースのテンプレートローダーを使いますが、 Django には、他のソースからテンプレートを読み込むことができる、他のテンプレートローダーがいくつか付属しています。
これらのローダーのいくつかはデフォルトでは無効になっていますが、 DjangoTemplates バックエンドの TEMPLATES 設定に 'loaders' オプションを追加するか、 Engine に loaders 引数を渡すことで有効にできます。 loaders は文字列かタプルのリストで、それぞれがテンプレートローダークラスを表します。以下は Django に付属のテンプレートローダーです:
django.template.loaders.filesystem.Loader
- class filesystem.Loader¶
DIRSに従ってファイルシステムからテンプレートを読み込みます。このローダーはデフォルトで有効になっています。しかし、
DIRSを空でないリストに設定しないとテンプレートを見つけられません:TEMPLATES = [ { "BACKEND": "django.template.backends.django.DjangoTemplates", "DIRS": [BASE_DIR / "templates"], } ]
また、
'DIRS'をオーバーライドして、特定のファイルシステムローダーに特定のディレクトリを指定することもできます:TEMPLATES = [ { "BACKEND": "django.template.backends.django.DjangoTemplates", "OPTIONS": { "loaders": [ ( "django.template.loaders.filesystem.Loader", [BASE_DIR / "templates"], ), ], }, } ]
django.template.loaders.app_directories.Loader
- class app_directories.Loader¶
ファイルシステム上の Django アプリからテンプレートを読み込みます。
INSTALLED_APPSにあるアプリごとに、ローダーはtemplatesサブディレクトリを探します。そのディレクトリが存在すれば、 Django はその中にあるテンプレートを探します。つまり、テンプレートを個々のアプリと一緒に保存できます。 また、Django アプリをデフォルトのテンプレートと一緒に配布するのにも役立ちます。
たとえば、この設定の場合:
INSTALLED_APPS = ["myproject.polls", "myproject.music"]
...上記のようにすると、
get_template('foo.html')はこれらのディレクトリのfoo.htmlをこの順番で探します:/path/to/myproject/polls/templates//path/to/myproject/music/templates/
...そして最初に見つけたものを使います。
INSTALLED_APPSの順序は重要です!例えば、Django管理サイトをカスタマイズしたい場合、django.contrib.adminの標準テンプレートadmin/base_site.htmlを、myproject.polls内の独自のadmin/base_site.htmlで上書きしたいかもしれません。その場合、myproject.pollsがINSTALLED_APPSでdjango.contrib.adminよりも 前に 来るように確認する必要があります。そうしないと、django.contrib.adminのものが先にロードされ、あなたのものは無視されます。ローダーは最初に実行されるときに最適化を行うことに注意してください。それは、どの
INSTALLED_APPSパッケージがtemplatesサブディレクトリを持っているかのリストをキャッシュします。このローダーを有効にするには
APP_DIRSをTrue: に設定します:TEMPLATES = [ { "BACKEND": "django.template.backends.django.DjangoTemplates", "APP_DIRS": True, } ]
django.template.loaders.cached.Loader
- class cached.Loader¶
Django のテンプレートシステムは非常に高速ですが、テンプレートがレンダリングされるたびにテンプレートを読み込んでコンパイルする必要がある場合、そのオーバヘッドは増大する可能性があります。
キャッシュされたテンプレートローダーは、それがラップすべき他のローダーのリストで構成されます。ラップされたローダーは、初めて遭遇した未知のテンプレートを見つけるために使用されます。その後、キャッシュされたローダーはコンパイルされた
Templateをメモリに保存します。同じテンプレートをロードするための後続のリクエストには、キャッシュされたTemplateインスタンスが返されます。このローダーは
OPTIONS['loaders']が指定されていない場合に自動的に有効になります。カスタムテンプレートローダーでは、以下のような設定を使ってテンプレートのキャッシュを手動で指定できます:
TEMPLATES = [ { "BACKEND": "django.template.backends.django.DjangoTemplates", "DIRS": [BASE_DIR / "templates"], "OPTIONS": { "loaders": [ ( "django.template.loaders.cached.Loader", [ "django.template.loaders.filesystem.Loader", "django.template.loaders.app_directories.Loader", "path.to.custom.Loader", ], ), ], }, } ]
注釈
Django 組み込みのテンプレートタグはすべてキャッシュローダで安全に使えますが、サードパーティのパッケージや自分で書いたカスタムテンプレートタグを使う場合は、各タグの
Node実装がスレッドセーフであることを確認する必要があります。詳細は テンプレートタグのスレッド安全性についての注意事項 を参照してください。
django.template.loaders.locmem.Loader
- class locmem.Loader¶
Python 辞書からテンプレートを読み込みます。これはテストに便利です。
このローダーはテンプレートの辞書を第一引数に取ります:
TEMPLATES = [ { "BACKEND": "django.template.backends.django.DjangoTemplates", "OPTIONS": { "loaders": [ ( "django.template.loaders.locmem.Loader", { "index.html": "content here", }, ), ], }, } ]
このローダーはデフォルトでは無効です。
Django は 'loaders' オプションに従って、テンプレートローダーを順番に使用します。一致するローダーが見つかるまで、それぞれのローダーを使います。
カスタムローダー¶
カスタムテンプレートローダーを使って、追加のソースからテンプレートをロードできます。カスタム Loader クラスは django.template.loaders.base.Loader を継承し、 get_contents() と get_template_sources() メソッドを定義する必要があります。
ローダーのメソッド¶
- class Loader[ソース]¶
ファイルシステムやデータベースなど、指定されたソースからテンプレートを読み込みます。
- get_template_sources(template_name)[ソース]¶
テンプレート名
template_nameを受け取り、Originインスタンスを生成するメソッドです。For example, the filesystem loader may receive
'index.html'as atemplate_nameargument. This method would yield origins for the full path ofindex.htmlas it appears in each template directory the loader looks at.メソッドは与えられたパスにテンプレートが存在することを確認する必要はありませんが、パスが有効であることを確認する必要があります。例えば、ファイルシステムローダーはパスが有効なテンプレートディレクトリのもとにあることを確認します。
- get_contents(origin)¶
与えられた
Originに対するテンプレートのコンテンツを返します。これは、ファイルシステムローダーがファイルシステムから内容を読み取る場所、またはデータベースローダーがデータベースから読み取る場所です。一致するテンプレートが存在しない場合、これは
TemplateDoesNotExistエラーを発生させるべきです。
- get_template(template_name, skip=None)[ソース]¶
get_template_sources()の結果をループしてget_contents()を呼び出すことで、与えられたtemplate_nameに対応するTemplateオブジェクトを返します。これは最初にマッチしたテンプレートを返します。テンプレートが見つからない場合、TemplateDoesNotExistが発生します。オプションの
skip引数はテンプレートを拡張するときに無視するオリジンのリストです。これにより、テンプレートが同じ名前の他のテンプレートを継承できるようになります。また、再帰エラーを回避するためにも使用されます。通常、カスタムテンプレートローダーは
get_template_sources()とget_contents()を定義すれば十分です。get_template()は通常オーバーライドする必要はありません。
自作する場合
例については、 Django の組み込みローダーのソースコード を読んでください。
テンプレート・オリジン¶
テンプレートは読み込むソースに応じた属性を含む origin を持ちます。
- class Origin(name, template_name=None, loader=None)[ソース]¶
- name¶
テンプレートローダーが返すテンプレートへのパス。ファイルシステムから読み込むローダーの場合、これはテンプレートへのフルパスです。
テンプレートがテンプレートローダーを通してではなく、直接インスタンス化された場合、これは
<unknown_source>という文字列値となります。
- template_name¶
テンプレートローダーに渡されるテンプレートへの相対パス。
テンプレートがテンプレートローダーを通してではなく、直接インスタンス化された場合、これは
Noneです。
- loader¶
この
Originを構築したテンプレートローダーインスタンス。テンプレートがテンプレートローダーを通してではなく、直接インスタンス化された場合、これは
Noneです。django.template.loaders.cached.Loaderは、ラップされたローダー全てにこの属性を要求します。通常、Originをloader=selfでインスタンス化します。