Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Jinja for loop scope is reset when incrementing variable

I am building a Flask app and am trying to loop through order lines to display the amount of items in a basket.

{% set items = 0 %}
{% for line in current_order.order_lines %} #loops twice in current test
    {% set items = items + line.quantity %} #should add 5 then 2
{% endfor %}

{{ items }} #outputs 0

After some research I've found it is a scope issue, i.e. the bottom {{ items }} can't see that I have added 5 then 2. How can I increment a value in a Jinja for loop?

like image 969
Andrew Bruce Avatar asked Feb 22 '18 20:02

Andrew Bruce


1 Answers

This is indeed a scoping issue, as documented in the Jinja2 template reference:

Scoping Behavior

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.

[...]

As of version 2.10 more complex use cases can be handled using namespace objects which allow propagating of changes across scopes[.]

So you could use the namespace() class as a work-around:

{% set ns = namespace(items=0) %}
{% for line in current_order.order_lines %}
    {% set ns.items = ns.items + line.quantity %}
{% endfor %}

{{ ns.items }}

That said, it is much better if you calculated the item count up front and passed this into the template as part of the current_order object or additional context.

Another option is to use the sum() filter to sum those quantities:

{% for line in current_order.order_lines %} #loops twice in current test
    <!-- render order line -->
{% endfor %}

{{ current_order.order_lines|sum(attribute='quantity') }}
like image 66
Martijn Pieters Avatar answered Nov 14 '22 22:11

Martijn Pieters