あらまし
Jinjaのselectattrフィルターにハマったのでメモ。
困ったこと
import jinja2
params = [
{
'class': 'A',
'name': '太郎',
},
{
'class': 'B',
'name': '花子',
},
]
env = jinja2.Environment()
tmpl = env.from_string('''
{%- if params | selectattr('class','==','C') %}
Cクラスの人はいますね
{%- endif %}
''')
print(tmpl.render(params))
とすると、Cクラスの人はいますね
と表示されてしまう。
なぜこうなるのか
selectattr
が返すのはジェネレータであるため。
tmpl = env.from_string('''
{{ params | selectattr('class','==','C') }}
''')
print(tmpl.render(params))
<generator object select_or_reject at 0x000001DBFB6A3140>
if
は空リストであれば偽と判定するが、
今回の場合はジェネレータオブジェクトを渡しており、これ自体は偽と判定されない。
(ジェネレータであることと、ジェネレータが何も要素を返さないのは別の話)
対策
list
フィルターに通すのがいいかと思う。
これでselectattr
の結果要素が見つからなかった場合は空リストになり、
if
で偽と判定できる。
tmpl = env.from_string('''
{%- if params | selectattr('class','==','C') | list %}
Cクラスの人はいますね
{%- endif %}
''')
print(tmpl.render(params))
⇒何も表示されない。
別解
独自の test を実装してもいいかも。
def existing(itr):
try:
next(iter(itr))
except StopIteration:
return False
else:
return True
env.tests['existing'] = existing
tmpl = env.from_string('''
{%- if params | selectattr('class','==','C') is existing %}
Cクラスの人はいますね
{%- endif %}
''')
print(tmpl.render(params))
今見てみたら
ドキュメントに「Similar to a generator comprehension such as:」とか書いてあった・・・
でもこれでselectattr
が返すのはジェネレータだと気付くのは無理じゃない・・・?
今後のために
普段のPythonコーディングで気にしていることだが、
Jinjaにおいても型を意識することは重要である。