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)¶ django.template.Context
のコンストラクタは、オプションの引数(変数名と変数の値をマッピングした辞書)を取ります。詳細は以下の 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 }}
これを防ぐには、呼び出し可能オブジェクトに
alters_data
属性を指定します。テンプレートシステムはalters_data=True
が設定された変数を呼び出さず、代わりに無条件でstring_if_invalid
に置き換えます。 動的に生成される Django モデルオブジェクトのdelete()
とsave()
メソッドは自動的にalters_data=True
を取得します。例:def sensitive_function(self): self.database_record.delete() sensitive_function.alters_data = True
時には、別の理由でこの機能をオフにし、何があっても呼び出されない変数を残すようにテンプレートシステムに指示したいことがあるかもしれません。 そのためには、呼び出し可能オブジェクトの
do_not_call_in_templates
属性をTrue
に設定します。 そうすると、テンプレートシステムはあたかも変数が呼び出し可能でないかのように動作します(たとえば、呼び出し可能オブジェクトの属性にアクセスできます)。
無効な変数の扱い¶
通常、変数が存在しない場合、テンプレートシステムはエンジンの 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
()¶
-
exception
ContextPopException
¶
コンテキストオブジェクトはスタックです。つまり、 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'
-
Context.
update
(other_dict)¶
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)¶
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.debug",
"django.template.context_processors.request",
"django.contrib.auth.context_processors.auth",
"django.contrib.messages.context_processors.messages",
]
上記に加えて、RequestContext
は常に 'django.template.context_processors.csrf'
を使えるようにしています。これは、admin や他の contrib アプリケーションで必要な、セキュリティ関連のコンテキストプロセッサで、設定ミスの場合に備えて意図的にハードコードされており、context_processors
オプション内で無効化できないようになっています。
各プロセッサは順番通りに適用されます。したがって、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
¶
-
auth
(request)¶
このプロセッサが有効な場合、全ての RequestContext
は以下の変数を含みます:
user
--auth.User
のインスタンスで、現在ログイン中のユーザ (あるいはログインしていない場合はAnonymousUser
のインスタンス) を表します。perms
--django.contrib.auth.context_processors.PermWrapper
のインスタンスで、現在ログイン中のユーザが有するパーミッションを表します。
django.template.context_processors.debug
¶
-
debug
(request)¶
このプロセッサが有効な場合、全ての RequestContext
は以下の 2 つの変数を含みます -- ただし、 DEBUG
設定が True
でリクエストの IP アドレス (request.META['REMOTE_ADDR']
) が INTERNAL_IPS
設定内にある場合のみです:
debug
--True
です。DEBUG
モードかどうかをテストするためにテンプレート内で使うことができます。sql_queries
--{'sql': ..., 'time': ...}
ディクショナリのリストで、リクエスト中に発生した全ての SQL クエリとかかった時間を表します。リストはデータベースエイリアス順、クエリ順です。アクセス上でレイジーに生成されます。
django.template.context_processors.i18n
¶
-
i18n
(request)¶
このプロセッサが有効な場合、全ての 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
¶
-
static
(request)¶
このプロセッサが有効な場合、全ての RequestContext
は変数 STATIC_URL
を含みます。これは、STATIC_URL
設定の値を提供します。
django.template.context_processors.csrf
¶
このプロセッサは、 クロスサイトリクエストフォージェリ (CSRF) 対策のための csrf_token
テンプレートタグが必要とするトークンを追加します。
django.template.context_processors.request
¶
このプロセッサが有効な場合、全ての RequestContext
は変数``request`` を含みます。これは現在の HttpRequest
です。
django.template.context_processors.tz
¶
-
tz
(request)¶
このプロセッサが有効な場合、全ての 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
インスタンスを生成するメソッドです。例えば、ファイルシステムローダーは
template_name
引数として'index.html'
を受け取るかもしれません。このメソッドは、ローダーが見る各テンプレートディレクトリ内のindex.html
の完全なパスに対してオリジンを生成します。メソッドは与えられたパスにテンプレートが存在することを確認する必要はありませんが、パスが有効であることを確認する必要があります。例えば、ファイルシステムローダーはパスが有効なテンプレートディレクトリのもとにあることを確認します。
-
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
でインスタンス化します。
-