DjangoBrothers BLOG ✍️

2019/11/19

このエントリーをはてなブックマークに追加
Django テンプレート

【Django】カスタムテンプレートフィルタ・テンプレートタグの作り方

こちらの記事ではDjangoのカスタムテンプレートフィルタ・タグ(Custom Template Tags and Filters)の実装方法について解説します。

テンプレートフィルタ・テンプレートタグとは

Djangoのテンプレートには、テンプレート側で処理を行う様々なタグやフィルタが用意されており、これをビルトイン・テンプレートフィルタ/タグと呼んでいます。

よく利用するDjangoのビルトイン・テンプレートタグの例としては、{% if ... %}{% for ... in ... %}などがあり、ビルトイン・テンプレートフィルタの例としては、lengthlinebreaksなどがあります。 {% %}で利用されるものがタグで、{{ }}で利用されるものがフィルタと考えて良いです。

Web開発でよく利用する機能についてはビルトイン・テンプレートフィルタ/タグを使えば事足りますが、Webサービスの要件が複雑になるほど、それらだけでは実現できないような機能も必要になることがあります。

そのためDjangoでは、自分でタグやフィルタを作ることができる機能を用意しており、これをカスタムテンプレートフィルタ/タグと呼びます。

カスタムテンプレートフィルタ/タグの作り方

カスタムテンプレートフィルタ/タグを作るには、3つのステップが必要です。

  1. アプリ内にtemplatetagsディレクトリを作成する
  2. templatetagsディレクトリ内に__init__.pyファイルを作成する
  3. templatetagsディレクトリ内にカスタムフィルタ・タグのファイルを作成する

カスタムフィルタ/タグを作成するには、templatetagsというディレクトリをアプリケーション内に作成し、その中にフィルタやタグのロジックを記述していきます。

その際に、templatetagsがモジュールであることを示すために__init__.pyという名前の空のファイルを作成することを忘れないようにしてください。

ディレクトリの構成は、例えば以下のようになります。これはappというアプリケーション内にmath_tags.pyというカスタムフィルタ/タグのファイルを作成するパターンになります。

appアプリケーションにカスタムフィルタ/タグを追加する

app/
    __init__.py
    models.py
    templatetags/
        __init__.py
        math_tags.py
    views.py

上記のようにカスタムフィルタ/タグを定義したら、テンプレート側でモジュールを呼び出し、実際にフィルタやタグを利用することができるようになります。

math_tagsモジュールをテンプレートで呼び出す

{% load math_tags %}

注意点として、{% load %}を利用するには、呼び出すモジュールを含むアプリケーションがINSTALLED_APPSに含まれていなければなりません。

カスタムテンプレートフィルタの作り方

カスタムフィルタの作成は、1つか2つの引数をとるPython関数を定義し、Djangoのテンプレートタグのライブラリに登録するというステップになります。

上記の例の、math_tags.pyに、二つの数字の掛け算を適用するフィルタを定義してみます。

app/templatetags/math_tags.py

from django import template

register = template.Library() # Djangoのテンプレートタグライブラリ

# カスタムフィルタとして登録する
@register.filter
def multiply(value1, value2):
    return value1 * value2

上記のように定義するだけで、テンプレート側で以下のようにフィルタを利用することができるようになります。

テンプレートでフィルタを呼び出す

{% load math_tags %}

<!-- num1=3, num2=4のとき、HTML上には12が表示される -->
<span>掛け算:{{ num1 | multiply:num2 }}</span>

上記の処理の場合、multiply関数の第一引数(value1)にnum1が、第二引数(value2)にnum2が渡され、結果が返ってきます。

これで、View側で掛け算を行った結果をテンプレートに返すのではなく、テンプレート上の変数を掛け合わせて表示することができるようになりました。

カスタムテンプレートタグの作り方

カスタムタグはフィルタよりも複雑な処理を扱うことができますが、カスタムフィルタで利用したmultiply関数の処理をカスタムタグで書いてみます。

※なお、カスタムテンプレートタグの作り方にはいくつか種類がありますが、ここでは最も一般的なsimple_tagを利用する方法を紹介します。

app/templatetags/math_tags.py

from django import template

register = template.Library() # Djangoのテンプレートタグライブラリ

# カスタムタグとして登録する
@register.simple_tag
def multiply(value1, value2):
    return value1 * value2

関数の定義は同じですが、simple_tagというデコレータ修飾しています。これでカスタムタグとして利用することができます。

テンプレートでタグを呼び出す

{% load math_tags %}

<!-- num1=3, num2=4のとき、HTML上には12が表示される -->
<span>掛け算:{% multiply num1 num2 %}</span>

フィルタとは呼び出し方が異なるので注意してください。

テンプレートフィルタとテンプレートタグの使い分け

テンプレートフィルタとテンプレートタグは似たような機能ですが、どのように使い分けるのが良いのでしょうか?

大きく、以下の二つのポイントがあると思います。

  • 関数の引数が2つ以下か?
  • ロジック内に、テンプレートコンテキスト(template context)を使うか?

カスタムフィルタは、その関数の引数を1つか2つにする必要があるため、それより多い引数が必要な場合には必然的にカスタムタグの方を利用せざるを得ません。

また、カスタムタグの方ではViewからTemplateに渡されるコンテクスト(テンプレート内で利用できる変数)を、そのロジック内で利用することができます。 そのため、基本的にはフィルタよりもタグの方が複雑な処理に向いています。『テンプレートでの表示の前に、少しだけ内容を修正したい』というレベルであればカスタムフィルタを、それ以上の複雑なロジックを組み合わせたいという場合であればカスタムタグを使いましょう。

参考

https://stackoverflow.com/questions/5586774/django-template-filters-tags-simple-tags-and-inclusion-tags