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

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

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

概要Link to this heading

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 にレンダリングを委譲します。

エンジンを設定するLink to this heading

もし 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)Link to this definition

Engine をインスタンス化する際は、すべての引数をキーワード引数として渡す必要があります:

  • dirs はエンジンがテンプレートのソースファイルを探すディレクトリのリストです。これは filesystem.Loader を設定するために使用されます。

    デフォルトは空のリストです。

  • app_dirsloaders のデフォルト値にだけ影響します。下記を参照してください。

    デフォルトは False です。

  • autoescape はHTMLのオートエスケープを有効にするかどうかをコントロールします。

    デフォルトは True です。

  • '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パスの辞書。これは新しいライブラリを追加したり、既存のライブラリの代替ラベルを提供するために使用します。たとえば下記のように:

    Code
    Engine(
        libraries={
            "myapp_tags": "path.to.myapp.tags",
            "admin.urls": "django.contrib.admin.templatetags.admin_urls",
        },
    )
    

    {% load %} タグに対応する辞書のキーを渡すことでライブラリをロードできます。

  • 'builtins': ビルトイン に追加するテンプレートタグモジュールのドット区切りPythonパスのリストです。たとえば:

    Code
    Engine(
        builtins=["myapp.builtins"],
    )
    

    {% load %} タグを呼び出さなくても、組み込みライブラリのタグやフィルタを使うことができます。

static Engine.get_default()Link to this definition

最初に設定された DjangoTemplates エンジンから Engine を返します。エンジンが設定されていない場合、 ImproperlyConfigured を発生させます。

これは、グローバルに利用可能で、暗黙的に設定されたエンジンに依存するAPIを保持するために必要です。それ以外の使用は強く推奨されません。

Engine.from_string(template_code)Link to this definition

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

Engine.get_template(template_name)Link to this definition

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

Engine.select_template(template_name_list)Link to this definition

get_template() と同様ですが、名前のリストを受け取り、最初に見つかったテンプレートを返します。

テンプレートを読み込むLink to this heading

Template を作成する推奨される方法は Engine のファクトリーメソッドを呼び出すことです。これは get_template(), select_template(), from_string() を指します。

TEMPLATES 設定で DjangoTemplates エンジンが定義されている Django プロジェクトでは、 Template を直接インスタンス化できます。複数の DjangoTemplates エンジンが定義されている場合、最初のものが使用されます。

class TemplateLink to this definition

このクラスは django.template.Template にあります。コンストラクタは1つの引数(生のテンプレートコード)を取ります:

Code
from django.template import Template

template = Template("My name is {{ my_name }}.")

コンテキストをレンダリングするLink to this heading

一度コンパイルされた Template オブジェクトがあれば、それを使ってコンテキストをレンダリングできます。同じテンプレートを再利用して、異なるコンテキストで何度でもレンダリングできます。

class Context(dict_=None, autoescape=True, use_l10n=None, use_tz=None)Link to this definition

django.template.Context のコンストラクタは、オプションの引数(変数名と変数の値をマッピングした辞書)を取ります。

3つのオプションのキーワード引数も指定できます:

  • autoescape はHTMLのオートエスケープを有効にするかどうかをコントロールします。

    デフォルトは True です。

  • use_l10n は、値がデフォルトでローカライズされるかどうかを上書きします。True に設定すると、数値や日付はロケールに基づいてフォーマットされます。

    デフォルトは None です。

    詳細は テンプレート内でローカライズをコントロールする を参照してください。

  • use_tz は、日付がテンプレートで表示される際にローカル時間に変換されるかどうかを上書きします。True に設定すると、すべての日付がローカルタイムゾーンを使用して表示されます。これは USE_TZ よりも優先されます。

    デフォルトは None です。

    詳細は テンプレートでのタイムゾーン aware な出力 を参照してください。

使用例については、下記の Context オブジェクトを使って遊ぶ を参照してください。

Template.render(context)Link to this definition

Context を指定して Template オブジェクトの render() メソッドを呼び出します:

Python console
>>> 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."

変数とルックアップLink to this heading

変数名はアルファベット(A-Z)、数字(0-9)、アンダースコア(ただしアンダースコアで始まってはならない)、ドットで構成されていなければなりません。

ドットはテンプレートレンダリングにおいて特別な意味を持ちます。変数名のドットは ルックアップ を意味します。具体的には、テンプレートシステムが変数名でドットを見つけると、以下の順番でルックアップを試みます:

  • 辞書のルックアップ。例: foo["bar"]

  • 属性のルックアップ。例: foo.bar

  • リストインデックスのルックアップ。例: foo[bar]

テンプレートコンテキストに変数 "bar "が存在する場合、{{ foo.bar }} のようなテンプレート式中の "bar "はリテラル文字列として解釈され、変数 "bar" の値は使用されないことに注意してください。

テンプレートシステムは、最初に機能するルックアップ・タイプを使用します。これは短絡ロジックです。以下はその例です:

Python console
>>> 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."

もし変数のどれかが呼び出し可能オブジェクトであれば、テンプレートシステムは呼び出しを試みます。例:

Python console
>>> 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 設定オプションの値(デフォルトでは空文字列)としてレンダリングされます。例:

    Python console
    >>> 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() メソッドです。テンプレートシステムはこのようなことをしてはいけません:

    Django template
    I will now delete this valuable data. {{ data.delete }}
    

    これを防ぐには、呼び出し可能オブジェクトに alters_data 属性を指定します。テンプレートシステムは alters_data=True が設定された変数を呼び出さず、代わりに無条件で string_if_invalid に置き換えます。 動的に生成される Django モデルオブジェクトの delete()save() メソッドは自動的に alters_data=True を取得します。例:

    Code
    def sensitive_function(self):
        self.database_record.delete()
    
    
    sensitive_function.alters_data = True
    
  • 時には、別の理由でこの機能をオフにし、何があっても呼び出されない変数を残すようにテンプレートシステムに指示したいことがあるかもしれません。 そのためには、呼び出し可能オブジェクトの do_not_call_in_templates 属性を True に設定します。 そうすると、テンプレートシステムはあたかも変数が呼び出し可能でないかのように動作します(たとえば、呼び出し可能オブジェクトの属性にアクセスできます)。

無効な変数の扱いLink to this heading

通常、変数が存在しない場合、テンプレートシステムはエンジンの string_if_invalid 設定オプションの値を挿入します。

string_if_invalid'' (空文字列) に設定されている場合のみ、無効な変数に適用されるフィルタが適用されます。もし string_if_invalid が他の値に設定されている場合、変数フィルタは無視されます。

この動作は if, for, regroup のテンプレートタグでは少し異なります。これらのテンプレートタグに無効な変数が指定された場合、その変数は None として解釈されます。これらのテンプレートタグ内の無効な変数には常にフィルタが適用されます。

もし string_if_invalid'%s' を含む場合、フォーマットマーカーは無効な変数名に置き換えられます。

組み込み変数Link to this heading

すべてのコンテキストは True, False, None を含みます。ご想像の通り、これらの変数は対応する Python オブジェクトに解決されます。

文字列リテラルの制約Link to this heading

Django のテンプレート言語には、独自の構文に使われる文字をエスケープする手段がありません。例えば、 {%%} のような文字列を出力する必要がある場合は、 templatetag タグが必要です。

これらのシーケンスをテンプレートフィルタやタグの引数に含めたい場合にも、同じような問題があります。例えば、ブロックタグを解析するとき、 Django のテンプレートパーサは {% の後に %} が最初に現れるかどうかを調べます。これは "%}" が文字列リテラルとして使われるのを阻止します。たとえば、以下のような式では TemplateSyntaxError が発生します:

Django template
{% include "template.html" tvar="Some string literal with %} in it." %}

{% with tvar="Some string literal with %} in it." %}{% endwith %}

フィルタの引数に予約済みのシーケンスを使用すると、同じ問題が発生することがあります:

Django template
{{ some.variable|default:"}}" }}

これらのシーケンスで文字列を使用する必要がある場合は、テンプレート変数に格納するか、カスタムテンプレートタグまたはフィルタを使用して制限を回避してください。

Context オブジェクトを使って遊ぶLink to this heading

たいていの場合、Context() に辞書を渡して Context オブジェクトをインスタンス化します。しかし、一度インスタンス化された Context オブジェクトに対しても、標準的な辞書構文を使ってアイテムの追加や削除を行うことができます:

Python console
>>> 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)Link to this definition

もし key がコンテキストに存在すれば key の値を返し、そうでなければ otherwise を返します。

Context.setdefault(key, default=None)Link to this definition

もし key がコンテキスト内にあれば、その値を返します。そうでない場合は、 default の値を持つ key を挿入し、 default を返します。

Context.pop()Link to this definition
Context.push()Link to this definition
exception ContextPopExceptionLink to this definition

コンテキストオブジェクトはスタックです。つまり、 push() したり pop() したりすることができます。 pop() しすぎると django.template.ContextPopException が発生します:

Python console
>>> 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() が呼び出されるようにすることもできます。

Python console
>>> c = Context()
>>> c["foo"] = "first level"
>>> with c.push():
...     c["foo"] = "second level"
...     c["foo"]
...
'second level'
>>> c["foo"]
'first level'

push() に渡されたすべての引数は、新しいコンテキストレベルを構築するために使用される dict コンストラクタに渡されます。

Python console
>>> c = Context()
>>> c["foo"] = "first level"
>>> with c.push(foo="second level"):
...     c["foo"]
...
'second level'
>>> c["foo"]
'first level'
Context.update(other_dict)Link to this definition

push()pop() に加えて、 Context オブジェクトは update() メソッドも定義しています。これは push() と同じように動作しますが、辞書を引数として受け取り、空の辞書の代わりにその辞書をスタックにプッシュします。

Python console
>>> 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() が呼び出されるようにすることができます。

Python console
>>> c = Context()
>>> c["foo"] = "first level"
>>> with c.update({"foo": "second level"}):
...     c["foo"]
...
'second level'
>>> c["foo"]
'first level'

スタックとして Context を使うと、 いくつかのテンプレートタグ で便利です。

Context.flatten()Link to this definition

flatten() メソッドを使うと、組み込み変数を含む Context スタック全体を一つの辞書として取得できます。

Python console
>>> 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 オブジェクトを比較できるようにするためにも使われています。

Python console
>>> 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 を比較するのに便利です:

Code
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 を使うLink to this heading

class RequestContext(request, dict_=None, processors=None, use_l10n=None, use_tz=None, autoescape=True)Link to this definition

Django には特別な Context クラスである django.template.RequestContext があり、通常の django.template.Context とは少し異なります。最初の違いは、 HttpRequest を最初の引数として取ることです。たとえば次のようになります。

Code
c = RequestContext(
    request,
    {
        "foo": "bar",
    },
)

2 つめの違いは、エンジンの context_processors 設定オプションによって、昆的に自動的にいくつかの変数をセットすることです。

context_processors オプションは callable -- context processors と呼ばれます -- のリストで、引数としてリクエストオブジェクトを受け取り、コンテキストに統合する項目のディクショナリを返します。 デフォルトで生成される設定ファイルでは、テンプレートエンジンは以下のコンテキストプロセッサを含んでいます:

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

また、省略可能な第 3 引数 processors を使って、RequestContext に追加的なプロセッサを渡すこともできます。以下の例では、RequestContext のインスタンスは ip_address 変数を格納します:

Code
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))

ビルトインのテンプレートコンテキストプロセッサLink to this heading

以下は、それぞれのビルトインのプロセッサが行うことです:

django.contrib.auth.context_processors.authLink to this heading

auth(request)Link to this definition

このプロセッサが有効な場合、全ての RequestContext は以下の変数を含みます:

  • user -- auth.User のインスタンスで、現在ログイン中のユーザ (あるいはログインしていない場合は AnonymousUser のインスタンス) を表します。

  • perms -- django.contrib.auth.context_processors.PermWrapper のインスタンスで、現在ログイン中のユーザが有するパーミッションを表します。

django.template.context_processors.debugLink to this heading

debug(request)Link to this definition

このプロセッサが有効な場合、全ての RequestContext は以下の 2 つの変数を含みます -- ただし、 DEBUG 設定が True でリクエストの IP アドレス (request.META['REMOTE_ADDR']) が INTERNAL_IPS 設定内にある場合のみです:

  • debug -- True です。DEBUG モードかどうかをテストするためにテンプレート内で使うことができます。

  • sql_queries -- {'sql': ..., 'time': ...} ディクショナリのリストで、リクエスト中に発生した全ての SQL クエリとかかった時間を表します。リストはデータベースエイリアス順、クエリ順です。アクセス上でレイジーに生成されます。

django.template.context_processors.i18nLink to this heading

i18n(request)Link to this definition

このプロセッサが有効な場合、全ての RequestContext は以下の変数を含みます:

  • LANGUAGES -- LANGUAGES 設定の値です。

  • LANGUAGE_BIDI -- 現在の言語がヘブライ語やアラビア語などの右から左へ書く言語の場合、 True を返します。英語、フランス語、ドイツ語などの左から右へ書く言語の場合は False です。

  • LANGUAGE_CODE -- 存在する場合は request.LANGUAGE_CODE で、それ以外の場合は LANGUAGE_CODE 設定です。

同じ値を生成するテンプレートタグについては i18n テンプレートタグ を参照してください。

django.template.context_processors.mediaLink to this heading

このプロセッサが有効な場合、全ての RequestContext は変数 MEDIA_URL を含みます。これは、 MEDIA_URL 設定の値を提供します。

django.template.context_processors.staticLink to this heading

static(request)Link to this definition

このプロセッサが有効な場合、全ての RequestContext は変数 STATIC_URL を含みます。これは、STATIC_URL 設定の値を提供します。

django.template.context_processors.csrfLink to this heading

このプロセッサは、 クロスサイトリクエストフォージェリ (CSRF) 対策のための csrf_token テンプレートタグが必要とするトークンを追加します。

django.template.context_processors.requestLink to this heading

このプロセッサが有効な場合、全ての RequestContext は変数``request`` を含みます。これは現在の HttpRequest です。

django.template.context_processors.tzLink to this heading

tz(request)Link to this definition

このプロセッサが有効な場合、全ての RequestContext は変数 TIME_ZONE を含みます。これは、現在アクティブなタイムゾーンの名前を提供します。

django.contrib.messages.context_processors.messagesLink to this heading

このプロセッサが有効な場合、全ての RequestContext は以下の 2 つの変数を含みます:

  • messages -- メッセージフレームワーク を通じてセットされた、(文字列としての) メッセージのリストです。

  • DEFAULT_MESSAGE_LEVELS -- 数値 のメッセージレベル名のマッピングです。

独自のコンテキストプロセッサを記述するLink to this heading

コンテキストプロセッサはシンプルなインタフェースを持っています。これは Python の関数で、 HttpRequest オブジェクトを引数に取り、テンプレートコンテキストに追加される辞書を返します。

たとえば、すべてのコンテキストに DEFAULT_FROM_EMAIL 設定を追加するには以下のようにします:

Code
from django.conf import settings


def from_email(request):
    return {
        "DEFAULT_FROM_EMAIL": settings.DEFAULT_FROM_EMAIL,
    }

カスタムコンテキストプロセッサはコードベースのどこにあっても構いません。Django が気にするのは、カスタムコンテキストプロセッサが TEMPLATES 設定の 'context_processors' オプションで指されているかどうか、直接使っている場合は Enginecontext_processors 引数で指されているかどうかだけです。

テンプレートを読み込むLink to this heading

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

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

DIRS オプションLink to this heading

設定ファイルの TEMPLATES 設定にある DIRS オプション、または Enginedirs 引数を使って、テンプレートディレクトリを Django に教えてください。これはテンプレートディレクトリへのフルパスを含む文字列のリストに設定する必要があります:

Code
TEMPLATES = [
    {
        "BACKEND": "django.template.backends.django.DjangoTemplates",
        "DIRS": [
            "/home/html/templates/lawrence.com",
            "/home/html/templates/default",
        ],
    },
]

ディレクトリとテンプレートがWebサーバーによって読み取れる限り、テンプレートはどこに置いても構いません。テンプレートの拡張子は .html.txt など好きなものを使うことができます。

これらのパスは、Windows でも Unix スタイルのスラッシュ (/) を使う必要があります。

ローダーの種類Link to this heading

デフォルトでは、 Django はファイルシステムベースのテンプレートローダーを使いますが、 Django には、他のソースからテンプレートを読み込むことができる、他のテンプレートローダーがいくつか付属しています。

これらのローダーのいくつかはデフォルトでは無効になっていますが、 DjangoTemplates バックエンドの TEMPLATES 設定に 'loaders' オプションを追加するか、 Engineloaders 引数を渡すことで有効にできます。 loaders は文字列かタプルのリストで、それぞれがテンプレートローダークラスを表します。以下は Django に付属のテンプレートローダーです:

django.template.loaders.filesystem.Loader

class filesystem.LoaderLink to this definition

DIRS に従ってファイルシステムからテンプレートを読み込みます。

このローダーはデフォルトで有効になっています。しかし、 DIRS を空でないリストに設定しないとテンプレートを見つけられません:

Code
TEMPLATES = [
    {
        "BACKEND": "django.template.backends.django.DjangoTemplates",
        "DIRS": [BASE_DIR / "templates"],
    }
]

また、'DIRS' をオーバーライドして、特定のファイルシステムローダーに特定のディレクトリを指定することもできます:

Code
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.LoaderLink to this definition

ファイルシステム上の Django アプリからテンプレートを読み込みます。 INSTALLED_APPS にあるアプリごとに、ローダーは templates サブディレクトリを探します。そのディレクトリが存在すれば、 Django はその中にあるテンプレートを探します。

つまり、テンプレートを個々のアプリと一緒に保存できます。 また、Django アプリをデフォルトのテンプレートと一緒に配布するのにも役立ちます。

たとえば、この設定の場合:

Code
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: に設定します:

Code
TEMPLATES = [
    {
        "BACKEND": "django.template.backends.django.DjangoTemplates",
        "APP_DIRS": True,
    }
]

django.template.loaders.cached.Loader

class cached.LoaderLink to this definition

Django のテンプレートシステムは非常に高速ですが、テンプレートがレンダリングされるたびにテンプレートを読み込んでコンパイルする必要がある場合、そのオーバヘッドは増大する可能性があります。

キャッシュされたテンプレートローダーは、それがラップすべき他のローダーのリストで構成されます。ラップされたローダーは、初めて遭遇した未知のテンプレートを見つけるために使用されます。その後、キャッシュされたローダーはコンパイルされた Template をメモリに保存します。同じテンプレートをロードするための後続のリクエストには、キャッシュされた Template インスタンスが返されます。

このローダーは OPTIONS['loaders'] が指定されていない場合に自動的に有効になります。

カスタムテンプレートローダーでは、以下のような設定を使ってテンプレートのキャッシュを手動で指定できます:

Code
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.template.loaders.locmem.Loader

class locmem.LoaderLink to this definition

Python 辞書からテンプレートを読み込みます。これはテストに便利です。

このローダーはテンプレートの辞書を第一引数に取ります:

Code
TEMPLATES = [
    {
        "BACKEND": "django.template.backends.django.DjangoTemplates",
        "OPTIONS": {
            "loaders": [
                (
                    "django.template.loaders.locmem.Loader",
                    {
                        "index.html": "content here",
                    },
                ),
            ],
        },
    }
]

このローダーはデフォルトでは無効です。

Django は 'loaders' オプションに従って、テンプレートローダーを順番に使用します。一致するローダーが見つかるまで、それぞれのローダーを使います。

カスタムローダーLink to this heading

カスタムテンプレートローダーを使って、追加のソースからテンプレートをロードできます。カスタム Loader クラスは django.template.loaders.base.Loader を継承し、 get_contents()get_template_sources() メソッドを定義する必要があります。

ローダーのメソッドLink to this heading

class LoaderLink to this definition

ファイルシステムやデータベースなど、指定されたソースからテンプレートを読み込みます。

get_template_sources(template_name)Link to this definition

テンプレート名 template_name を受け取り、 Origin インスタンスを生成するメソッドです。

例えば、ファイルシステムローダーは template_name 引数として 'index.html' を受け取るかもしれません。このメソッドは、ローダーが見る各テンプレートディレクトリ内の index.html の完全なパスに対してオリジンを生成します。

メソッドは与えられたパスにテンプレートが存在することを確認する必要はありませんが、パスが有効であることを確認する必要があります。例えば、ファイルシステムローダーはパスが有効なテンプレートディレクトリのもとにあることを確認します。

get_contents(origin)Link to this definition

与えられた Origin に対するテンプレートのコンテンツを返します。

これは、ファイルシステムローダーがファイルシステムから内容を読み取る場所、またはデータベースローダーがデータベースから読み取る場所です。一致するテンプレートが存在しない場合、これは TemplateDoesNotExist エラーを発生させるべきです。

get_template(template_name, skip=None)Link to this definition

get_template_sources() の結果をループして get_contents() を呼び出すことで、与えられた template_name に対応する Template オブジェクトを返します。これは最初にマッチしたテンプレートを返します。テンプレートが見つからない場合、 TemplateDoesNotExist が発生します。

オプションの skip 引数はテンプレートを拡張するときに無視するオリジンのリストです。これにより、テンプレートが同じ名前の他のテンプレートを継承できるようになります。また、再帰エラーを回避するためにも使用されます。

通常、カスタムテンプレートローダーは get_template_sources()get_contents() を定義すれば十分です。 get_template() は通常オーバーライドする必要はありません。

テンプレート・オリジンLink to this heading

テンプレートは読み込むソースに応じた属性を含む origin を持ちます。

class Origin(name, template_name=None, loader=None)Link to this definition
nameLink to this definition

テンプレートローダーが返すテンプレートへのパス。ファイルシステムから読み込むローダーの場合、これはテンプレートへのフルパスです。

テンプレートがテンプレートローダーを通してではなく、直接インスタンス化された場合、これは <unknown_source> という文字列値となります。

template_nameLink to this definition

テンプレートローダーに渡されるテンプレートへの相対パス。

テンプレートがテンプレートローダーを通してではなく、直接インスタンス化された場合、これは None です。

loaderLink to this definition

この Origin を構築したテンプレートローダーインスタンス。

テンプレートがテンプレートローダーを通してではなく、直接インスタンス化された場合、これは None です。

django.template.loaders.cached.Loader は、ラップされたローダー全てにこの属性を要求します。通常、 Originloader=self でインスタンス化します。