I want to loop over a list of objects and count how many objects meet a requirement. I based my code off other examples I'd found, but it doesn't work, the count is always 0 after the loop.
For each house, I want to loop over each room and count how many rooms have a bed. I want to output that then reset the count for the next house.
{% 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 %}
Jinja 2.10 introduces the namespace
object to handle assignment and comparison in loops.
{% 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.
Normally, set
does not handle attributes, which is why the old answers mutate objects with methods instead. namespace
has been special cased so setting attributes does work.
The reason the original counter didn't work is because of Jinja's scope rules. Unlike Python, most blocks are new scopes. set
always defines a local variable, except in this new special case of namespace.attribute
.
In this specific case, you can accomplish what you want with filters.
{% set beds = house.rooms|selectattr('has_bed')|length %}
{{ house.address }} has {{ beds }} beds.
However, there are cases where storing information across scopes is needed. For example, if you wanted to output some information in addition to incrementing the counter, it would make sense to use a namespace
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With