最近、データ分析等でPythonをやり始めたばかりで、どうせならWebViewもPythonでやろうとDjangoを利用していた際に、テンプレート側から辞書オブジェクトを参照するために、カスタムフィルタを作成して参照しようとしたところ、ハマった箇所があったのでここにメモしておきます。
カスタムフィルタ
Djangoのテンプレートで呼び出し可能な関数の一つ
http://django-docs-ja.readthedocs.org/en/latest/howto/custom-template-tags.html
辞書オブジェクトを参照するカスタムフィルタ
templatetags/helper.py
from django import template
register = template.Library()
def get_dict_val(var,args):
dict_val = var
keys = [arg.strip() for arg in args.split(',')]
for key in keys:
dict_val = dict_val[key]
return dict_val
register.filter('dict_val',get_dict_val)
- テンプレート側
{{ dict_obj|get_dict_val:'key1,key2' }}
この方法で辞書オブジェクトに参照が出来ます。
カンマで区切ることで多階層のオブジェクトまで参照可能です。
{"1":{"0001":"営業部"}}
しかし、この方法だとテンプレート側からの引数は文字列でないと処理が出来ないため、変数をカスタムフィルタに渡すことが出来ません。(forループ内の処理のオブジェクト等)
- テンプレート側
# エラー
{% for row in data %}
<p>{{ dict_obj|get_dict_val:row.no,row.busho_code }}</p>
{% endfor %}
結論
1度、2つの変数をカンマで区切り文字列を作成、その後引数に渡すという形を取りました。
- カスタムフィルタにカンマで結合する関数を追加
templatetags/helper.py
def join_comma(var,args):
return "%s,%s" % (var,args)
register.filter('join_comma',join_comma)
- テンプレート側
withテンプレートタグを使用することで一時的に変数を作成することが可能
{% for row in data %}
{% with row.no|join_comma:row.busho_code as shain_id %}
<p>{{ dict_obj|get_dict_val:shain_id }}</p>
{% endwith %}
{% endfor %}
カスタムフィルタの引数については今までも議論があるようです
https://code.djangoproject.com/ticket/1199
なるべくview側で済ませる設計にする必要があると思いますが、仕様上どうしてもテンプレート側で辞書オブジェクトに直接アクセスしないといけない状況も出てくるかもしれないので、やり方を上記に残しておきました。