Djangoで変数や定数を連結して使う。
単純にフィルタを使えばいい。ビルトインのフィルタにadd
があるが、int
向けな設計なようでstr
では使わない方がいいかもしれないと思ったのがきっかけ。
やること
- テンプレートタグ用のディレクトリを
app
直下に作る。 - 作法に従ってフィルタを書く。
- テンプレートでモジュールをロードする。
- テンプレートで書いたフィルタを使う。
公式で大体説明されている:
以下、フィルタのソースを見て、フィルタを作り、使えるようにするまでをメモしておく。
ビルトインの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 ''
参照元ページ:
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関連書籍(広告)