テンプレート

Django はウェブフレームワークなので、HTML を動的に生成する便利な手段が必要でした。最も一般的なアプローチは、テンプレートに頼ることです。テンプレートには、出力したい HTML を書いた静的な部分と、動的なコンテンツを挿入する方法を書いた特別な構文の部分からなります。テンプレートを使って HTML ページを作るハンズオンの例については、チュートリアル 3 を見てください。

Django プロジェクトは、1つまたは複数のテンプレートエンジンで構成できます (テンプレートを使わなければ、ゼロでも構いません)。Django は、Django テンプレート言語 (DTL) と呼ばれる独自のテンプレートシステムや、人気のある代替テンプレートである Jinja2 用のバックエンドをビルトインで同梱しています。他のテンプレート言語用のバックエンドはサードパーティから入手できるかもしれません。 カスタムテンプレートバックエンド を参照してください。

Django は、バックエンドにかかわらず使用できる、テンプレートの読み込みとレンダリングのための標準の API を定義しています。読み込みのパートでは、指定された名前からテンプレートを探し、テンプレートを前処理し、通常はメモリ上のデータに変換します。レンダリングのパートでは、テンプレートの中にコンテキストデータを埋め込み、最終的な文字列を返します。

Django テンプレート言語 (DTL) はDjango 用のテンプレートシステムです。Django 1.8 までは、ビルトインのオプションしか選択できませんでした。小さな癖もありますが、とても良いテンプレートライブラリです。他のバックエンドを無理して選択しなければならない特別な理由がない限り、DTL を使用することをおすすめします。アプリケーションを書いてテンプレートを配布しようと考えている場合は、特にそうです。たとえば、Django のテンプレートを含んでいる django.contrib.admin のような contrib アプリは、DTL を使用しています。

歴史的な理由により、テンプレートエンジンの一般的なサポートと Django テンプレート言語の実装は、両方とも django.template 名前空間に定義されています。

警告

テンプレートシステムは、信頼できないテンプレートの作者に対しては安全ではありません。たとえば、サイトではユーザー自身がテンプレートを送信できるようにしてはなりません。テンプレートの作者は XSS 攻撃と同様のことが可能になり、テンプレート変数の属性にアクセスして、秘密にしなければならない情報にアクセスできてしまう可能性があるからです。

Django テンプレート言語

構文

このセクションについて

このセクションで紹介するのは、Django テンプレート言語の構文の概要です。詳細については、 言語構文のリファレンス を参照してください。

Django テンプレートは、 Django テンプレート言語を使ってマークアップされたテキスト文書や Python 文字列です。いくつかの構文はテンプレートエンジンによって認識され、解釈されます。主なものは変数とタグです。

テンプレートは、コンテキストともにレンダリングされます。レンダリングでは、変数が見つかると、コンテキスト内に記録された変数の値に置換され、タグが実行されます。それ以外の文字列は、そのまま出力されます。

Django テンプレート言語の構文は、4つの構成要素に分類できます。

変数

変数は、コンテキストから値を出力します。コンテキストは、キーと値をマッピングする辞書のようなオブジェクトです。

変数はこのように {{}} で囲まれます:

My first name is {{ first_name }}. My last name is {{ last_name }}.

コンテキストが {'first_name': 'John', 'last_name': 'Doe'} の場合、このテンプレートは次のようにレンダリングされます:

My first name is John. My last name is Doe.

辞書ルックアップ、属性ルックアップ、リストインデックスルックアップはドット記法で実装されています:

{{ my_dict.key }}
{{ my_object.attribute }}
{{ my_list.0 }}

変数が呼び出し可能オブジェクトに解決される場合、テンプレート・システムは引数なしで呼び出し、呼び出し可能オブジェクトの代わりにその結果を使用します。

タグ

タグはレンダリングプロセスにおいて任意のロジックを提供します。

この定義は意図的に曖昧にしてあります。たとえば、タグはコンテンツを出力したり、 "if" 文や "for" ループなどの制御構造として提供したり、データベースからコンテンツを取得したり、あるいは他のテンプレートタグへのアクセスを可能にしたりすることができます。

タグはこのように {%%} で囲まれます:

{% csrf_token %}

ほとんどのタグは引数を受け付けます:

{% cycle 'odd' 'even' %}

タグによっては開始タグと終了タグが必要です:

{% if user.is_authenticated %}Hello, {{ user.username }}.{% endif %}

関連項目: 組み込みタグのリファレンス独自のテンプレートタグの書き方

フィルタ

フィルタは変数やタグの引数の値を変換します。

たとえばこのようなものです:

{{ django|title }}

コンテキストを {'django': 'the web framework for perfectionists with deadlines'} とすると、このテンプレートは次のようにレンダリングされます:

The Web Framework For Perfectionists With Deadlines

引数を必要とするフィルタもあります:

{{ my_date|date:"Y-m-d" }}

関連項目: 組み込みフィルタのリファレンス独自のテンプレートフィルタの書き方

Comments

コメントはこのように書きます:

{# this won't be rendered #}

{% comment %} タグで複数行のコメントを書けます。

コンポーネント

このセクションについて

このセクションで紹介するのは、Django テンプレート言語の API の概要です。詳細については、API リファレンス をご覧ください。

エンジン

django.template.Engine は Django テンプレートシステムのインスタンスをカプセル化します。 Engine を直接インスタンス化する主な理由は、 Django プロジェクトの外で Django テンプレート言語を使うためです。

django.template.backends.django.DjangoTemplates は、 django.template.Engine を Django のテンプレートバックエンド API に適応させる薄いラッパーです。

テンプレート

django.template.Template はコンパイルされたテンプレートを表します。テンプレートは Engine.get_template() または Engine.from_string() で取得できます。

同様に django.template.backends.django.Templatedjango.template.Template を一般的なテンプレート API に適応させるための薄いラッパーです。

コンテキスト

django.template.Context はコンテキストデータの他にいくつかのメタデータを保持します。これはテンプレートをレンダリングするために Template.render() に渡されます。

django.template.RequestContextContext のサブクラスで、現在の HttpRequest を保存し、テンプレートコンテキストプロセッサを実行します。

共通 API には等価な概念がありません。コンテキストデータはプレーンな dict で渡され、現在の HttpRequest は必要に応じて別途渡されます。

ローダー

テンプレートローダーが責任を持つのは、テンプレートの検索、テンプレートの読み込み、Template オブジェクトを返すことです。

Django はいくつかの ビルトインのテンプレートローダー を提供していて、 カスタム テンプレートローダー をサポートしています。

コンテキストプロセッサ

コンテキストプロセッサは、現在の HttpRequest を引数としておけとり、データの dict をレンダリングコンテキストに追加して返します。

主な用途は、すべてのビューでコードを繰り返すことなく、すべてのテンプレートで共有される共通のデータをコンテキストに追加することです。

Django は多くの 組み込みのコンテキストプロセッサ を提供し、独自のコンテキストプロセッサを追加実装することもできます。

テンプレートエンジンのサポート

設定

テンプレートエンジンは、TEMPLATES で設定できます。ここには、各エンジンに対する設定のリストを設定します。デフォルト値は空リストです。startproject コマンドで生成された settings.py には、以下のように便利な値がいくつか設定されます。

TEMPLATES = [
    {
        "BACKEND": "django.template.backends.django.DjangoTemplates",
        "DIRS": [],
        "APP_DIRS": True,
        "OPTIONS": {
            # ... some options here ...
        },
    },
]

BACKEND は、Django テンプレートバックエンド API を実装したテンプレートエンジンのクラスへの、ドット区切りの Python path です。ビルトインのバックエンドは、django.template.backends.django.DjangoTemplatesdjango.template.backends.jinja2.Jinja2 です。

ほとんどのエンジンはファイルからテンプレートを読み込むため、各エンジンのトップレベルの設定には次の2つの設定があります。

  • DIRS には、エンジンがテンプレートのソースファイルを検索するディレクトリのリストを、検索順に定義します。
  • APP_DIRS には、エンジンがインストールしたアプリケーション内のテンプレートを検索するべきかどうかを指定します。各バックエンドは、アプリケーション内でテンプレートを保存するべきサブディレクトリ名として、慣習的な名前を定義しています。

めったにないことですが、同じバックエンドの複数のインスタンスを、オプションだけ変えて設定することも可能です。その場合、各エンジンに対して、NAME にユニークな名前を設定しなければなりません。

OPTIONS には、バックエンド特有の設定を書きます。

使い方

django.template.loader モジュールは、テンプレートを読み込むための2つの関数を定義しています。

get_template(template_name, using=None)[ソース]

この関数は、指定した名前のテンプレートを読み込み、Template オブジェクトを返します。

戻り値の正確な型はテンプレートを読み込んだバックエンドに依存します。それぞれのバックエンドは独自の Template クラスを持っています。

get_template() は各テンプレートエンジンを見つけるまで順番に試します。テンプレートが見つからない場合、 TemplateDoesNotExist を発生します。テンプレートが見つかったが無効な構文を含んでいる場合、 TemplateSyntaxError を発生します。

テンプレートがどのように検索され読み込まれるかは、各エンジンのバックエンドと設定によって異なります。

検索を特定のテンプレートエンジンに限定したい場合は、 using 引数にそのエンジンの NAME を渡します。

select_template(template_name_list, using=None)[ソース]

select_template()get_template() に似ていますが、1つのテンプレート名の代わりにテンプレート名のリストを取ります。各名前のテンプレートを順番に探し、最初に見つかったテンプレートを返します。

テンプレートの読み込みに失敗した場合、 django.template で定義されている以下の2つの例外が発生する可能性があります:

exception TemplateDoesNotExist(msg, tried=None, backend=None, chain=None)[ソース]

この例外はテンプレートが見つからない場合に発生します。デバッグページの template postmortem に入力するために、以下のオプション引数を受け付けます:

backend
例外が発生したテンプレートバックエンドのインスタンス。
tried
テンプレートを見つける際に試されたソースのリスト。フォーマットは (origin, status) を含むタプルのリストです。ここで originorigin-like オブジェクトで、status はテンプレートが見つからなかった理由を表す文字列です。
chain
テンプレートを読み込もうとしたときに発生した例外 TemplateDoesNotExist の中間値のリストです。これは get_template() のような、与えられたテンプレートを複数のエンジンから読み込もうとする関数で使用されます。
exception TemplateSyntaxError(msg)[ソース]

この例外は、テンプレートが見つかったが、エラーを含んでいる場合に発生します。

get_template()select_template() が返す Template オブジェクトは以下のシグネチャを持つ render() メソッドを提供しなければなりません:

Template.render(context=None, request=None)

与えられたコンテキストを用いて、このテンプレートをレンダリングします。

context を指定する場合は、dict でなければなりません。もし指定しなければ、エンジンは空のコンテキストでレンダリングします。

request を指定する場合は、HttpRequest でなければなりません。テンプレートエンジンは、テンプレート内では、このインスタンスと CSRF トークンを使用できるようにする必要があります。そのための実装はバックエンドに依存します。

以下に、検索アルゴリズムの例を示します。この例の場合、TEMPLATES 設定は次のようになっています。

TEMPLATES = [
    {
        "BACKEND": "django.template.backends.django.DjangoTemplates",
        "DIRS": [
            "/home/html/example.com",
            "/home/html/default",
        ],
    },
    {
        "BACKEND": "django.template.backends.jinja2.Jinja2",
        "DIRS": [
            "/home/html/jinja2",
        ],
    },
]

get_template('story_detail.html') を呼び出した場合、Django は次の順番にファイルを探します。

  • /home/html/example.com/story_detail.html ('django' エンジン)
  • /home/html/default/story_detail.html ('django' エンジン)
  • /home/html/jinja2/story_detail.html ('jinja2' エンジン)

select_template(['story_253_detail.html', 'story_detail.html']) を呼び出した場合、Djangoは以下の順番にファイルを探します。

  • /home/html/example.com/story_253_detail.html ('django' エンジン)
  • /home/html/default/story_253_detail.html ('django' エンジン)
  • /home/html/jinja2/story_253_detail.html ('jinja2' エンジン)
  • /home/html/example.com/story_detail.html ('django' エンジン)
  • /home/html/default/story_detail.html ('django' エンジン)
  • /home/html/jinja2/story_detail.html ('jinja2' エンジン)

Django がテンプレートを発見したら、その時点で探索は停止します。

より柔軟性を求める場合は django.template.loader.select_template() を使ってください。

select_template() を使うと、柔軟にテンプレートを読み込むことができます。たとえば、ニュース記事を書いていて、いくつかの記事にカスタムテンプレートを持たせたい場合、 select_template(['story_%s_detail.html' % story.id, 'story_detail.html']) のように使います。これにより、個々のストーリーにカスタムテンプレートを使用することができ、カスタムテンプレートを持たないストーリーにはフォールバックテンプレートを使用できます。

テンプレートを含む各ディレクトリの中のサブディレクトリにテンプレートを整理することは可能であり、望ましいことです。慣習としては、Django アプリごとにサブディレクトリを作り、必要に応じてその中にサブディレクトリを作ります。

正気を保つためにも、そうしてください。すべてのテンプレートを1つのディレクトリのルートレベルに保存すると、面倒なことになります。

サブディレクトリ内のテンプレートを読み込むには、次のようにスラッシュを使います:

get_template("news/story_detail.html")

上記と同じ TEMPLATES オプションを使用すると、以下のテンプレートを読み込もうとします:

  • /home/html/example.com/news/story_detail.html ('django' エンジン)
  • /home/html/default/news/story_detail.html ('django' エンジン)
  • /home/html/jinja2/news/story_detail.html ('jinja2' エンジン)

さらに、テンプレートの読み込みやレンダリングの繰り返しを減らすために、Django は処理を自動化するショートカット関数を提供しています。

render_to_string(template_name, context=None, request=None, using=None)[ソース]

render_to_string()get_template() のようにテンプレートを読み込んで、すぐに render() メソッドを呼び出します。以下の引数を取ります。

template_name
読み込んでレンダリングするテンプレートの名前です。テンプレート名のリストの場合、 Django はテンプレートを見つけるのに get_template() の代わりに select_template() を使います。
context
レンダリングのためにテンプレートのコンテキストとして使用される dict です。
request
オプション HttpRequest で、テンプレートのレンダリング処理中に利用できます。
using
オプションのテンプレートエンジン NAME です。テンプレートの検索はそのエンジンに制限されます。

使用例:

from django.template.loader import render_to_string

rendered = render_to_string("my_template.html", {"foo": "bar"})

render() ショートカットも参照してください。このショートカットは render_to_string() を呼び出して、その結果をビューから返すのに適した HttpResponse に出力します。

最後に、設定されたエンジンを直接使用することもできます:

engines

テンプレートエンジンは django.template.engines で利用できます:

from django.template import engines

django_engine = engines["django"]
template = django_engine.from_string("Hello {{ name }}!")

ルックアップのキー (この例では 'django') はエンジンの NAME です。

組み込みのバックエンド

class DjangoTemplates[ソース]

Django テンプレートエンジンを設定するには、 BACKEND'django.template.backends.django.DjangoTemplates' にセットします。

APP_DIRSTrue の場合、 DjangoTemplates エンジンはインストールされたアプリケーションの templates サブディレクトリにあるテンプレートを探します。この一般名は後方互換性のために残されています。

DjangoTemplates エンジンは以下の OPTIONS を受け付けます:

  • 'autoescape': HTMLのオートエスケープを有効にするかどうかをコントロールする真偽値です。

    デフォルトは True です。

    警告

    HTML以外のテンプレートをレンダリングする場合のみ False に設定してください!

  • 'context_processors': リクエストでテンプレートがレンダリングされるときにコンテキストを生成するために使用される呼び出し可能オブジェクトへの Python のドット区切りパスのリストです。これらの呼び出し可能オブジェクトはリクエストオブジェクトを引数として取り、コンテキストにマージされるアイテムの dict を返します。

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

    詳しくは RequestContext を参照してください。

  • 'debug': テンプレートのデバッグモードのオン/オフを切り替える真偽値です。もし True なら、テンプレートのレンダリング中に例外が発生した場合、fancy エラーページに詳細なレポートが表示されます。このレポートには、該当する行がハイライトされたテンプレートのスニペットが含まれます。

    デフォルトは DEBUG 設定の値です。

  • 'loaders': テンプレートローダクラスへの Python のドット区切りパスのリストです。各 Loader クラスは特定のソースからテンプレートをインポートする方法を知っています。任意で、文字列の代わりにタプルを使うこともできます。タプルの最初の項目は Loader クラス名で、それ以降の項目は初期化時に Loader に渡されます。

    デフォルトは DIRSAPP_DIRS の値に依存します。

    詳しくは ローダーの種類 を参照してください。

  • 'string_if_invalid': 無効な(例えばスペルミスのある)変数に対してテンプレートシステムが使用する文字列です。

    デフォルトは空文字列です。

    詳しくは 無効な変数の扱い を参照してください。

  • 'file_charset': ディスク上のテンプレートファイルを読み込む際に使用する文字セットです。

    デフォルトは 'utf-8' です。

  • 'libraries': テンプレートエンジンに登録するテンプレートタグモジュールのラベルとドット区切りPythonパスの辞書。これは新しいライブラリを追加したり、既存のライブラリの代替ラベルを提供するために使用できます。たとえば:

    OPTIONS = {
        "libraries": {
            "myapp_tags": "path.to.myapp.tags",
            "admin.urls": "django.contrib.admin.templatetags.admin_urls",
        },
    }
    

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

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

    OPTIONS = {
        "builtins": ["myapp.builtins"],
    }
    

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

class Jinja2[ソース]

Jinja2 がインストールされている必要があります:

$ python -m pip install Jinja2
...\> py -m pip install Jinja2

Jinja2 エンジンを指定するには BACKEND'django.template.backends.jinja2.Jinja2' を設定します。

APP_DIRSTrue の場合、 Jinja2 エンジンはインストールされているアプリケーションの jinja2 サブディレクトリにあるテンプレートを探します。

OPTIONS の中で最も重要なエントリは 'environment' です。これはJinja2の環境を返す呼び出し可能オブジェクトへのPythonのドット区切りパスです。デフォルトは 'jinja2.Environment' です。Django はその呼び出し可能オブジェクトを起動し、他のオプションをキーワード引数として渡します。さらに、 Django はいくつかのオプションに Jinja2 とは異なるデフォルトを追加します:

  • 'autoescape': True
  • 'loader': DIRSAPP_DIRS に設定されたローダー。
  • 'auto_reload': settings.DEBUG
  • 'undefined': DebugUndefined if settings.DEBUG else Undefined

また、 Jinja2 エンジンは以下の OPTIONS も受け付けます:

  • 'context_processors': リクエストでテンプレートがレンダリングされるときにコンテキストを生成するために使用される呼び出し可能オブジェクトへの Python のドット区切りパスのリストです。これらの呼び出し可能オブジェクトはリクエストオブジェクトを引数として取り、コンテキストにマージされるアイテムの dict を返します。

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

    Jinja2テンプレートでコンテキストプロセッサを使用することは推奨されません。

    Django テンプレートは引数付き関数の呼び出しをサポートしていないので、 コンテキストプロセッサは Django テンプレートで有用です。Jinja2 にはその制限がないので、コンテキストプロセッサとして使う関数を jinja2.Environment を使ってテンプレートのグローバル変数に置くことをお勧めします。そうすれば、テンプレートの中でその関数を呼び出すことができます:

    {{ function(request) }}
    

    いくつかの Django テンプレートコンテキストプロセッサは固定値を返します。Jinja2 テンプレートでは、 jinja2.Environment で直接定数を追加できるので、このような間接的なレイヤーは不要です。

    Jinja2用のコンテキストプロセッサを追加する当初のユースケースは、次のようなものでした:

    • リクエストに依存する高コストな計算。
    • すべてのテンプレートで結果が必要な場合。
    • 各テンプレートで結果を複数回使用する場合。

    これらの条件がすべて満たされない限り、テンプレートに関数を渡す方が Jinja2 の設計に合っています。

デフォルトの設定は意図的に最小限に抑えられています。テンプレートがリクエストと共にレンダリングされる場合 (例えば render() を使用する場合)、 Jinja2 バックエンドは requestcsrf_input および csrf_token というグローバルをコンテキストに追加します。それ以外は、このバックエンドは Django フレーバーの環境を作りません。Django のフィルタやタグについては知りません。Django 固有の API を使うには、環境に設定する必要があります。

たとえば、下記のような内容の myproject/jinja2.py を作成することができ、:

from django.templatetags.static import static
from django.urls import reverse

from jinja2 import Environment


def environment(**options):
    env = Environment(**options)
    env.globals.update(
        {
            "static": static,
            "url": reverse,
        }
    )
    return env

これで 'environment' オプションを 'myproject.jinja2.environment' に設定できます。

そして、Jinja2 テンプレートで以下の構文を使用できるようになります:

<img src="{{ static('path/to/company-logo.png') }}" alt="Company Logo">

<a href="{{ url('admin:index') }}">Administration</a>

タグとフィルタの概念は Django テンプレート言語にも Jinja2 にもありますが、使い方が異なります。Jinja2 はテンプレートの呼び出し可能オブジェクトに引数を渡すことをサポートしているので、 Django テンプレートでテンプレートタグやフィルタを必要とする多くの機能は、上の例のように Jinja2 テンプレートで関数を呼び出すことで実現できます。Jinja2 のグローバル名前空間はテンプレートコンテキストプロセッサの必要性をなくします。Django テンプレート言語には Jinja2 のテストに等価なものはありません。

Back to Top