Python プログラマーのための Django テンプレート言語

この文書は Django テンプレートシステムがどのように動作し、どのように拡張するか、技術的な観点から説明します。構文に関するリファレンスを探しているなら、 Django テンプレート言語 を参照してください。

テンプレート、 コンテキスト、変数、タグ、レンダリングについての理解を前提としています。これらの概念に馴染みがなければ、 Django テンプレート言語入門 からスタートしてください。

概要

Pythonでテンプレートシステムを使うには3つのステップがあります:

  1. Engine を設定します。
  2. テンプレートコードを Template にコンパイルします。
  3. テンプレートを Context においてレンダリングします。

これらの各ステップで、Django プロジェクトは通常、テンプレートシステムの低レベルの API ではなく、 バックエンドに依存しない高レベルの API に依存しています:

  1. TEMPLATES 設定の中で、各 DjangoTemplates バックエンドに対して、Djangoは Engine をインスタンス化します。DjangoTemplatesEngine をラップし、共通のテンプレートバックエンドAPIに適応させます。
  2. django.template.loader モジュールはテンプレートを読み込むための get_template() のなどの関数を提供します。これらは実際の django.template.Template をラップした django.template.backends.django.Template を返します。
  3. 前のステップで取得した 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_dirsloaders のデフォルト値にだけ影響します。下記を参照してください。

    デフォルトは 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_dirsTrue の場合だけです。

    これらのローダーは 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.from_string(template_code)

与えられたテンプレートコードをコンパイルして Template オブジェクトを返します。

Engine.get_template(template_name)

与えられた名前のテンプレートを読み込んでコンパイルし、 Template オブジェクトを返します。

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() の結果は、ユニットテストで Contextdict を比較するのに便利です:

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 番目をオーバーライドします。デフォルトのプロセッサは以下で説明します。

コンテキストプロセッサが適用されたとき

コンテキストプロセッサは、コンテキストデータのトップに適用されます。これは、ContextRequestContext に与えた変数を、コンテキストプロセッサが上書きすることを意味します。コンテキストプロセッサによって提供される変数と、名前が重複しないように気をつけてください。

コンテキストデータをコンテキストプロセッサに優先させたい場合、以下のパターンを使ってください:

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' オプションで指されているかどうか、直接使っている場合は Enginecontext_processors 引数で指されているかどうかだけです。

テンプレートを読み込む

通常、テンプレートは低レベルの Template API を使うのではなく、ファイルシステム上のファイルに保存します。テンプレートは テンプレートディレクトリ として指定したディレクトリに保存します。

Django はテンプレート読み込みの設定によって、様々な場所でテンプレートディレクトリを探しますが (後述の 「ローダの種類」を参照してください)、テンプレートディレクトリを指定する最も基本的な方法は DIRS オプションを使うことです。

DIRS オプション

設定ファイルの TEMPLATES 設定にある DIRS オプション、または Enginedirs 引数を使って、テンプレートディレクトリを 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' オプションを追加するか、 Engineloaders 引数を渡すことで有効にできます。 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.pollsINSTALLED_APPSdjango.contrib.admin よりも 前に 来るように確認する必要があります。そうしないと、django.contrib.admin のものが先にロードされ、あなたのものは無視されます。

ローダーは最初に実行されるときに最適化を行うことに注意してください。それは、どの INSTALLED_APPS パッケージが templates サブディレクトリを持っているかのリストをキャッシュします。

このローダーを有効にするには APP_DIRSTrue: に設定します:

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 は、ラップされたローダー全てにこの属性を要求します。通常、 Originloader=self でインスタンス化します。

Back to Top