Jinja2: Change the value of a variable inside a loop

PythonJinja2

Python Problem Overview


I want to change the value of the variable declared outside the loop within a loop. But always changing, it keeps the initial value outside the loop.

{% set foo = False %}

{% for item in items %}
  {% set foo = True %}
  {% if foo %} Ok(1)! {% endif %}
{% endfor %}

{% if foo %} Ok(2)! {% endif %}

This renders:

Ok(1)!

So the only (bad) solution have found so far was this:

{% set foo = [] %}

{% for item in items %}
  {% if foo.append(True) %} {% endif %}
  {% if foo %} Ok(1)! {% endif %}
{% endfor %}

{% if foo %} Ok(2)! {% endif %}

This renders:

Ok(1)!
Ok(2)!

But, its is very ugly! Is there another more elegant solution?

Python Solutions


Solution 1 - Python

Try also dictionary-based approach. It seems to be less ugly.

{% set vars = {'foo': False} %}

{% for item in items %}
  {% if vars.update({'foo': True}) %} {% endif %}
  {% if vars.foo %} Ok(1)! {% endif %}
{% endfor %}

{% if vars.foo %} Ok(2)! {% endif %}

This also renders:

Ok(1)!
Ok(2)!

Solution 2 - Python

as mentioned in the documentation: > Please note that assignments in loops will be cleared at the end of > the iteration and cannot outlive the loop scope.

but as of version 2.10 you can use namespaces:

    {% set ns = namespace(foo=false) %}      
    {% for item in items %}
      {% set ns.foo = True %}
      {% if ns.foo %} Ok(1)! {% endif %}
    {% endfor %}
    
    {% if ns.foo %} Ok(2)! {% endif %}

Solution 3 - Python

You could do this to clean up the template code

{% for item in items %}
  {{ set_foo_is_true(local_vars) }}
  {% if local_vars.foo %} Ok(1)! {% endif %}
{% endfor %}
{% if local_vars.foo %} Ok(2)! {% endif %}

And in the server code use

items = ['item1', 'item2', 'item3']
#---------------------------------------------
local_vars = { 'foo': False }
def set_foo_is_true(local_vars):
  local_vars['foo'] = True
  return ''
env.globals['set_foo_is_true'] = set_foo_is_true    
#---------------------------------------------
return env.get_template('template.html').render(items=items, local_vars=local_vars)

This could be generalized to the following

{{ set_local_var(local_vars, "foo", False) }}
{% for item in items %}
  {{ set_local_var(local_vars, "foo", True) }}
  {% if local_vars.foo %} Ok(1)! {% endif %}
{% endfor %}
{% if local_vars.foo %} Ok(2)! {% endif %}

And in the server code use

items = ['item1', 'item2', 'item3']
#---------------------------------------------
local_vars = { 'foo': False }
def set_local_var(local_vars, name, value):
  local_vars[name] = value
  return ''
env.globals['set_local_var'] = set_local_var
#---------------------------------------------
return env.get_template('template.html').render(items=items, local_vars=local_vars)

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionShankar CabusView Question on Stackoverflow
Solution 1 - PythonPashkaView Answer on Stackoverflow
Solution 2 - PythonOmerView Answer on Stackoverflow
Solution 3 - PythonDaniel FView Answer on Stackoverflow