如何选择/减少Flask / Jinja中的词典列表

时间:2013-12-11 20:26:28

标签: python flask jinja2

我有一个带有词典列表的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测试检查两个对象是否真的是内存中的同一对象,而不是两个字符串/数字是否相等。

那么可以根据键/值比较测试来选择项目吗?

6 个答案:

答案 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>