テンプレートのバックエンドをカスタマイズする

カスタムのバックエンド

ここでは、他のテンプレートシステムを使用するために、カスタムテンプレートバックエンドを実装する方法を説明します。テンプレートバックエンドは django.template.backends.base.BaseEngine を継承したクラスです。このクラスは get_template() と、オプションで from_string() を実装する必要があります。以下は架空の foobar テンプレートライブラリの例です:

from django.template import TemplateDoesNotExist, TemplateSyntaxError
from django.template.backends.base import BaseEngine
from django.template.backends.utils import csrf_input_lazy, csrf_token_lazy

import foobar


class FooBar(BaseEngine):
    # Name of the subdirectory containing the templates for this engine
    # inside an installed application.
    app_dirname = "foobar"

    def __init__(self, params):
        params = params.copy()
        options = params.pop("OPTIONS").copy()
        super().__init__(params)

        self.engine = foobar.Engine(**options)

    def from_string(self, template_code):
        try:
            return Template(self.engine.from_string(template_code))
        except foobar.TemplateCompilationFailed as exc:
            raise TemplateSyntaxError(exc.args)

    def get_template(self, template_name):
        try:
            return Template(self.engine.get_template(template_name))
        except foobar.TemplateNotFound as exc:
            raise TemplateDoesNotExist(exc.args, backend=self)
        except foobar.TemplateCompilationFailed as exc:
            raise TemplateSyntaxError(exc.args)


class Template:
    def __init__(self, template):
        self.template = template

    def render(self, context=None, request=None):
        if context is None:
            context = {}
        if request is not None:
            context["request"] = request
            context["csrf_input"] = csrf_input_lazy(request)
            context["csrf_token"] = csrf_token_lazy(request)
        return self.template.render(context)

詳しい情報は DEP 182 を参照してください。

カスタムエンジンに対するデバッグの統合

Django のデバッグページには、テンプレートエラーが発生したときに詳細な情報を提供するフックがあります。カスタムのテンプレートエンジンは、これらのフックを使うことで、ユーザに表示されるトレースバック情報を強化できます。以下のフックが利用できます:

テンプレートの postmortem (事後分析)

postmortemは TemplateDoesNotExist が発生したときに表示されます。これは、指定されたテンプレートを見つけようとしたときに使われたテンプレートエンジンとローダの一覧を表示します。例えば、2つの Django エンジンが設定されている場合、 postmortem は以下のように表示されます:

../../_images/postmortem.png

カスタムエンジンは TemplateDoesNotExist を発生させるときに backendtried 引数を渡すことで postmortem に値を入れることができます。postmortem を使用するバックエンドはテンプレートオブジェクトの origin を指定する 必要があります。

コンテキストの行情報

もしテンプレートをパースもしくはレンダリングしてる最中にエラーが発生したら、Djangoはエラーが発生した行を表示することができます。たとえば:

../../_images/template-lines.png

カスタムエンジンはパースやレンダリング中に発生した例外に template_debug 属性を指定することで、この情報を入力できます。この属性は以下の値を持つ dict です:

  • 'name': 例外が発生したテンプレートの名前。
  • 'message': 例外メッセージ。
  • 'source_lines': 例外が発生した行の前後の行。これは文脈のためのものなので、20行以上にすべきではありません。
  • 'line': 例外が発生した行番号。
  • 'before': エラーを発生させたトークンの前のエラー行の内容。
  • 'during': エラーを発生させたトークン。
  • 'after': エラーを発生させたトークンの後のエラー行の内容。
  • 'total': source_lines の行数。
  • 'top': source_lines が始まる行番号。
  • 'bottom': source_lines が終了する行番号。

上記のテンプレートエラーが発生した場合、 template_debug は次のようになります:

{
    "name": "/path/to/template.html",
    "message": "Invalid block tag: 'syntax'",
    "source_lines": [
        (1, "some\n"),
        (2, "lines\n"),
        (3, "before\n"),
        (4, "Hello {% syntax error %} {{ world }}\n"),
        (5, "some\n"),
        (6, "lines\n"),
        (7, "after\n"),
        (8, ""),
    ],
    "line": 4,
    "before": "Hello ",
    "during": "{% syntax error %}",
    "after": " {{ world }}\n",
    "total": 9,
    "bottom": 9,
    "top": 1,
}

Origin API と サードパーティとの統合

Django templates have an Origin object available through the template.origin attribute. This enables debug information to be displayed in the template postmortem, as well as in 3rd-party libraries, like the Django Debug Toolbar.

カスタムエンジンは、以下の属性を指定するオブジェクトを作成することで、独自の template.origin 情報を提供できます:

  • 'name': テンプレートへのフルパス。
  • 'template_name': テンプレート読み込みメソッドに渡される、テンプレートへの相対パス。
  • 'loader_name': テンプレートの読み込みに使われる関数またはクラスを識別するためのオプションの文字列。例: django.template.loaders.filesystem.Loader
Back to Top