Django テンプレートで文字列を連結する

Djangoで変数や定数を連結して使う。

単純にフィルタを使えばいい。ビルトインのフィルタにaddがあるが、int向けな設計なようでstrでは使わない方がいいかもしれないと思ったのがきっかけ。

やること

  • テンプレートタグ用のディレクトリをapp直下に作る。
  • 作法に従ってフィルタを書く。
  • テンプレートでモジュールをロードする。
  • テンプレートで書いたフィルタを使う。

公式で大体説明されている:

独自のテンプレートタグとフィルタ | Django ドキュメント
The web framework for perfectionists with deadlines.

以下、フィルタのソースを見て、フィルタを作り、使えるようにするまでをメモしておく。

ビルトインのaddをみてみる

githubでソースを見ると、下記のようになっている。

@register.filter(is_safe=False)
def add(value, arg):
    """Add the arg to the value."""
    try:
        return int(value) + int(arg)
    except (ValueError, TypeError):
        try:
            return value + arg
        except Exception:
            return ''

参照元ページ:

django/django/template/defaultfilters.py at main · django/django
The Web framework for perfectionists with deadlines. - django/django

intを優先して試行するようだ。その後プラス演算子のサポートに依存する感じ。これなら文字列の連結も十分できる。 しかし、int試行で無駄なコストがかかるので、やはりこのフィルタは文字列連結目的では使わずにおこう。

フィルタを作成

addstrというフィルタを作成する。.pyファイルは<app>/templatetags/内に格納しろとのこと。

# <app>/templatetags/app_tags.py

@register.filter(name='addstr')
def addstr(value, arg):
    """ Only concat string argument """
    if isinstance(arg, str):
        return value + arg
    else:
        return value

一応引数がstrかどうかのチェックを挟んでいるが、strしか使わない確信があればなくてもいい。(率直にいえば+演算子が使えればstrでなくとも問題はない。) またstrでないときは何もフィルタせずにそのまま値を通している。ここは用途や方針によって変えていいところだろう。

テンプレートからロード可能にする

<app>をDjangoの設定ファイルのINSTALLED_APPSに含める。すでに追加済みかもしれない。

これだけでテンプレートからロード可能になる。

{% load app_tags %}

<p>{{ msgheader|addstr:message }}</p>

これで文字列の連結が楽になる。このフィルタを複数回通すことで文字列は次々と連結可能。少し見た目が悪いのが玉に瑕だが。

おわりに

文字列の連結ができれば、テンプレート内の変数を作成しやすくなる。

それによりwithタグなどと一緒に使えば動的なスタティックパスの生成が容易にできる。

...省略...

{% with "fixedpath/"|addstr:name|addstr:".png" as filename %}
<img src="{% static filename %}">
{% endwith %}

...

といったような実装ができる。これを実現したくてaddフィルタに目を止めたのが本音。 strと分かっているものをintにしようとしてしまう挙動は嫌だったのでカスタムフィルタで対応した。

手軽にフィルタを独自で作れるのはとてもいい。

以上です。


Django関連書籍(広告)

https://amzn.to/35ZvFLt
タイトルとURLをコピーしました