在Jinja for循环中设置变量并不会在迭代之间保持

时间:2017-10-25 18:35:04

标签: python jinja2

我想循环一个对象列表并计算满足要求的对象数量。我将我的代码基于我发现的其他示例,但它不起作用,循环后计数始终为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 个答案:

答案 0 :(得分:3)

对于Jinja 2.9,范围行为已修复,使先前版本中的代码无效。增量值count仅存在于循环范围内。 Their example涉及设置变量,但概念是相同的:

  

请记住,无法在块内设置变量并将其显示在块外。这也适用于循环。该规则的唯一例外是if语句不引入范围。因此,以下模板无法实现您的预​​期:

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

使用Jinja语法无法做到这一点。

为了在迭代中跟踪count,您需要执行hacky-ish解决方法。设置一个列表,附加到它,然后计算它的长度。

{% 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 %}

答案 1 :(得分:2)

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的scope rules。与Python不同,大多数块都是新作用域。 set始终定义一个局部变量,但在namespace.attribute这一新的特殊情况下除外。


在这种情况下,您可以使用过滤器完成所需的操作。

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

但是,在某些情况下,需要跨作用域存储信息。例如,如果您除了要增加计数器之外还想输出一些信息,那么使用namespace就是有意义的。

答案 2 :(得分:0)

对于Jinja&lt; = 2.8,您显示的代码确实有效。然而,这是由于Jinja的范围规则中的{{3}},其定义为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 %}