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

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

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

やること

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

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

独自のテンプレートタグとフィルタ | Django ドキュメント | Django

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

ビルトインの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
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関連書籍(広告)

現場で使える Django の教科書《基礎編》 | 横瀬 明仁 |本 | 通販 | Amazon
Amazonで横瀬 明仁の現場で使える Django の教科書《基礎編》。アマゾンならポイント還元本が多数。横瀬 明仁作品ほか、お急ぎ便対象商品は当日お届けも可能。また現場で使える Django の教科書《基礎編》もアマゾン配送商品なら通常配送無料。
タイトルとURLをコピーしました