1.この記事の内容
Django templateからネストされた辞書変数に対してkeyを動的に変えながらアクセスする方法を紹介します.
実装例全体は,筆者のGitHubで公開していますので,詳細はこちらをご確認ください.
2.背景
Django templateから辞書変数にアクセスするには下記のように. (ドット)
指定することでアクセスできます.
dict_data = {
'key1': 0,
'key2': 1,
}
{{ dict_data.key1 }}
アクセスするキーが決まっているならこれでよいのですが,キー名(key1, key2)が決まっていない場合に,単純に変数を. (ドット)
で繋ぐことはできません.
dict_data = {
'key1': 0,
'key2': 1,
}
dict_key = 'key1'
{{ dict_data.dict_key }} ← このような指定はできない(Key Error)
この問題を,ネストされた辞書変数に対しても解決できる実装例を紹介します.
3.対策例
3-1.単純な辞書変数
カスタムフィルタを使って,値を取得することができます.
こちらは実装方法がシンプルなので,記事本文のみに例を記載します.
@register.filter
def get_value(value, key):
if (key in value.keys()):
return value[key]
else:
return None
dict_data = {
'key1': 0,
'key2': 1,
}
dict_key = 'key1'
{% load custom_filter %}
{{ dict_data|get_value:dict_key }}
3-2.ネストされた辞書変数
ネストされた辞書変数にアクセスするには複数のキーをカスタムフィルタに渡す必要がありますが,カスタムフィルタは引数を1つだけしか扱えず,少し工夫が必要です.
実装のポイントは2点,
- 複数のキーを区切り文字を含めた一つの文字列を作り,カスタムフィルタの引数とする
- カスタムフィルタの処理内で,区切り文字でキーを分解する
です.
以下,実装例ですが,少し長いので折りたたんでます.
カスタムフィルタの実装例(ここをクリックで展開)
@register.filter
def dict_value(value, args):
""" Get Dict Value from Nested Dict Object
Get value from nested dictionary object.
Args:
value: object
args (string): specify the strings comma separated
"""
if ((args is not None) and (args != '')):
arg_list = [arg.strip() for arg in args.split(',')]
keys = None
_value = value
for key in arg_list[:-1]:
keys = _value[key].keys()
_value = _value[key]
return _value[arg_list[-1]]
else:
return None
ネストされた辞書変数の実装例(ここをクリックで展開)
- 記事での説明用に,GitHub上のコードから少し変えています
def implementations(request):
nested_dict = {
'key1': {
'key1-1': {
'val_A': '11A',
'val_B': '11B',
'val_C': '11C',
'val_D': '11D',
'val_E': '11E',
},
'key1-2': {
'val_A': '12A',
'val_B': '12B',
'val_C': '12C',
},
'key1-3': {
'val_A': '13A',
'val_B': '13B',
'val_C': '13C',
'val_D': '13D',
},
'key1-4': {
'val_A': '14A',
'val_B': '14B',
},
},
'key2': {
'key2-1': {
'val_A': '21A',
'val_B': '21B',
},
'key2-2': {
'val_A': '22A',
'val_B': '22B',
'val_C': '22C',
'val_D': '22D',
},
'key2-3': {
'val_A': '23A',
'val_B': '23B',
'val_C': '23C',
'val_D': '23D',
'val_E': '23E',
},
},
'key3': {
'key3-1': {
'val_A': '31A',
'val_B': '31B',
},
'key3-2': {
'val_A': '32A',
'val_B': '32B',
'val_C': '32C',
'val_D': '32D',
'val_E': '32E',
},
},
}
key1 = 'key2'
key2 = 'key2-2'
key3 = 'val_B'
templateの実装例(ここをクリックで展開)
- 記事での説明用に,GitHub上のコードから少し変えています
- この例ではカンマ区切りの文字列をカスタムフィルタの引数としています
-
with
文を用いて変数key
に連結した文字列を代入し,カスタムフィルタdict_value
に渡します - この実装方法で,
key1
,key2
,key3
を変えることで,ネストされた辞書変数nested_dict
へ動的にアクセスすることができます
{% load custom_filter %}
{% with key1|:","|add:key2|:","|add:key3 as key %}
{{ nested_dict|dict_value:key }}
{% endwith %}
4.さいごに
templateからネストされた辞書変数に動的に指定する実装例を紹介しました.
ネストされた辞書変数に限らず,カスタムフィルタへ複数の引数を指定したいときにも流用できると思います.