Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Why does using set in a jinja template not persistently change the value from the perspective of later content?

I’m trying to use the jinja2 moudle… It’s working differently than I expected.

The value of the variable has_swimming should change within the for loop, but it resets to the initial value.

The code below is intended to perform a function that finds instances where the hobby is SWIMMING in a list of dictionaries, and wraps them with the desired String characters above and below.

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

from jinja2 import Environment

if __name__ == '__main__':
    template = \
        '''
{% set has_swimming = 0 %}

{% for row in Class['Students'] %}
{% set name = row['name'] -%}
{% set hobby = row['hobby'] %}
    {% if hobby == 'SWIMMING' and has_swimming == 0 %}
        {% set has_swimming = 1 %}
find swim=============
    {% endif %}
name is {{name}}, hobby is {{hobby}}
    {% if hobby != 'SWIMMING' and has_swimming == 1 %}
        {% set has_swimming = 0 %}
end===============
    {% endif %}
{% endfor %}

{% if has_swimming == 1%}
end===============
{% endif %}
        '''

    env = Environment(extensions=['jinja2.ext.i18n', 'jinja2.ext.do', 'jinja2.ext.loopcontrols'],
                      trim_blocks=True, lstrip_blocks=True)
    new_template = env.from_string(template)
    test_table = dict()
    test_table['Class'] = dict()
    test_table['Class']['Students'] = list()
    test_table['Class']['Students'].append({'name': 'CHOI', 'hobby': 'RUNNINg'})
    test_table['Class']['Students'].append({'name': 'KIM', 'hobby': 'RUNNINg'})
    test_table['Class']['Students'].append({'name': 'JEON', 'hobby': 'SWIMMING'})
    test_table['Class']['Students'].append({'name': 'YOON', 'hobby': 'SWIMMING'})
    write_text = new_template.render(test_table)
    print(write_text)

I have a question about the initialization of the has_swimming variable in the code above.

The code {% set has_swimming = 0 %} initializes the variable to 0 before entering the for loop.

Then, if the hobby of the current row is ‘swimming’,

{% if hobby == 'SWIMMING' and has_swimming == 0 %}
        {% set has_swimming = 1 %}

Current output result:

name is CHOI, hobby is RUNNINg
name is KIM, hobby is RUNNINg
find swim=============
name is JEON, hobby is SWIMMING
find swim=============
name is YOON, hobby is SWIMMING

Expected output result:

name is CHOI, hobby is RUNNINg
name is KIM, hobby is RUNNINg
find swim=============
name is JEON, hobby is SWIMMING
name is YOON, hobby is SWIMMING
end===============

I can’t understand, the has_swimming value should be set ‘1’, but on next row, value of has_swimming resets to zero…

>Solution :

The end=============== is never printed because the assignment {% set has_swimming = 1 %} is limited to inside the surrounding loop block. Per the documentation for the for block from the Jinja2 docs:

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

This behavior is also further discussed under Assignments:

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 a workaround (in Jina 2.10+), you can use a namespace object to create assignments that propagate to outer scopes:

{% set ns = namespace(has_swimming=false) %}
{% for row in Class['Students'] %}
    {# ... #}

    {% if hobby == 'SWIMMING' and not ns.has_swimming %}
        {% set ns.has_swimming = true %}
    {% endif %}

    {# ... #}

{% endfor %}

{% if ns.has_swimming %}
    {# ... #}
{% endif %}
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading