Jinja中在循环中设置的变量在迭代之间不会持久化

9
我想要遍历一个对象列表并计算出满足特定条件的对象数量。我参考了其他示例代码,但是它不起作用,循环后计数总是为0。

对于每个房子,我想要遍历每个房间并计算有多少个房间有床。我想要输出结果然后将计数器重置为下一所房子。

{% for house in city %}
{% set count = 0 %}
    <div>{{ house.address }} has {{ count }} beds in it rooms.</div>
    {% for room in house %}
    {% if room.has_bed == True %}{% set count = count + 1 %}{% endif %}
   {% endfor %}
{% endfor %}
3个回答

21

Jinja 2.10 引入 namespace 对象以在循环中处理赋值和比较。

{% set ns = namespace(beds=0) %}
{% for room in house %}
    {% if room.has_bed %}
        {% set ns.beds = ns.beds + 1 %}
    {% endif %}
{% endfor %}
{{ house.address }} has {{ ns.beds }} beds.

通常情况下,set不处理属性,这就是为什么旧的答案使用方法改变对象的原因。namespace被特殊处理以使设置属性起作用。

原始计数器无法正常工作的原因是Jinja的作用域规则。与Python不同,大多数块都是新范围。 set始终定义局部变量,除了这个新的特殊情况:namespace.attribute


在这种特定情况下,您可以使用过滤器实现所需功能。

{% set beds = house.rooms|selectattr('has_bed')|length %}
{{ house.address }} has {{ beds }} beds.

然而,有些情况下需要跨作用域存储信息。例如,如果您想要在递增计数器的同时输出一些信息,使用 namespace 就是合理的选择。


6

对于Jinja 2.9,作用域行为已经修复,这使得之前版本的代码失效。 count 的递增值仅在循环范围内生效。他们的示例涉及设置变量,但概念是相同的:

Please keep in mind that it is not possible to set variables inside a block and have them show up outside of it. This also applies to loops. The only exception to that rule are if statements which do not introduce a scope. As a result the following template is not going to do what you might expect:

{% set iterated = false %}
{% for item in seq %}
    {{ item }}
    {% set iterated = true %}
{% endfor %}
{% if not iterated %} did not iterate {% endif %}

It is not possible with Jinja syntax to do this.

你需要做一个巧妙的解决方法,以便在迭代过程中跟踪 count。设置一个列表,将其附加到其中,然后计算其长度。
{% for house in city %}
    {% set room_count = [] %}
    {% for room in house %}
        {% if room.has_bed %}
            {% if room_count.append(1) %}{% endif %}
        {% endif %}
    {% endfor %}
    <div>{{ house.address }} has {{ room_count|length }} beds.</div>
{% endfor %}

0

对于 Jinja <= 2.8,你展示的代码确实可以工作。然而,这是由于 Jinja 的作用域规则中存在 不正确的行为,这在 2.9 中已经得到修复。

{% for house in city %}
    {% set count = 0 %}
    {% for room in house %}
        {% if room.has_bed %}
            {% set count = count + 1 %}
        {% endif %}
    {% endfor %}
    <div>{{ house.address }} has {{ count }} beds.</div>
{% endfor %}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接