我有一个带有词典列表的Jinja模板。订单很重要。我想根据字典的键/值减少列表或查找值。这是一个例子:
{%
set ordered_dicts = [
{
'id': 'foo',
'name': 'My name is Foo'
},
{
'id': 'bar',
'name': 'My name is Bar'
}
]
%}
如果我有变量some_id = 'foo'
,如何在我的Jinja模板中从'My name is Foo'
中获取ordered_dicts
?
我尝试了select()
和selectattr()
但根据文档无法弄清楚它们。这是我试过的:
{{ ordered_dicts|selectattr("id", "foo") }}
输出:
<generator object _select_or_reject at 0x10748d870>
我认为我不能正确理解select()
和selectattr()
的用法。
我是否需要遍历列表并手动执行查找?
更新:
正如codegeek和gipi指出的那样,我需要用生成器做这样的事情:
{{ ordered_dicts|selectattr("id", "foo")|list }}
结果错误:TemplateRuntimeError: no test named 'foo'
,阐明了selectattr()
的工作原理。第二个参数必须是the builtin tests之一。据我所知,这些测试都不会让我检查与键相关的值是否与另一个值匹配。这就是我想做的事情:
{{ ordered_dicts|selectattr("id", "sameas", "foo")|list }}
但这不起作用,因为sameas
测试检查两个对象是否真的是内存中的同一对象,而不是两个字符串/数字是否相等。
那么可以根据键/值比较测试来选择项目吗?
答案 0 :(得分:22)
我刚刚向后移equalto
:
app.jinja_env.tests['equalto'] = lambda value, other : value == other
之后this example from 2.8 docs有效:
{{ users|selectattr("email", "equalto", "foo@bar.invalid") }}
更新:Flask有一个用于注册测试的装饰器,语法稍微清晰:http://flask.pocoo.org/docs/api/#flask.Flask.template_test
答案 1 :(得分:3)
对于那些没有选择权限的人(例如你还没有使用Jinja2.6),并且不想制作另一个自定义过滤器,这2行将真正快速解决您的问题
{% set selection = [] %}
{% for x in biglist if x.criteria == 'pickme' %}{% do selection.append(x) %}{% endfor %}
答案 2 :(得分:2)
请查看https://github.com/ansible/ansible/issues/8836此问题。
解决方案/解决方法是在工作簿目录中创建一个文件filter_plugins / core.py,其中包含以下内容:
def filter_list(list, key, value):
return filter(lambda t: t[key] == value, list)
class FilterModule(object):
def filters(self):
return {
'byattr': filter_list
}
并使用它:
{{ ordered_dicts|byattr("id", "foo") }}
答案 3 :(得分:1)
select()
和selectattr()
对list
采取行动并返回list
,因此如果您知道只有一个结果从发生器获取第一个,即< / p>
{{ oredered_dicts|selectattr("id", "foo")|first }}
注意:代码未经过测试
答案 4 :(得分:1)
Ansible的更自然的方法是创建包含内容的/etc/ansible/test_plugins/custom.py
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
from ansible import errors
def equalto(value, other):
return bool(value == other)
class TestModule(object):
''' Ansible file jinja2 tests '''
def tests(self):
return {
'equalto' : equalto,
}
答案 5 :(得分:0)
看起来 equalto 过滤器出现在Jinja2.8(changelog)中,但它还没有设置任何发布日期(2014年2月24日)。作为一种解决方法,我建议使用 groupby 过滤器:
<ul>
{% for group in persons|groupby('gender') %}
<li>{{ group.grouper }}<ul>
{% for person in group.list %}
<li>{{ person.first_name }} {{ person.last_name }}</li>
{% endfor %}</ul></li>
{% endfor %}
</ul>