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
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
.