c00p3r.web
c00p3r.web

Reputation: 848

Jinja2: local/global variable

{% set disabled = '' %}
{% for voter in record.voters %}
    {% if user == voter %}
        {% set disabled = 'disabled' %}
    {% endif %}
    {{ disabled }}  # outputs: 'disabled'
{% endfor %}
{{ disabled }}  # outputs: ''

I have that template in Jinja2. What I need is 'disabled' variable to be visible outside 'for' loop. Is that possible?

Upvotes: 14

Views: 42473

Answers (5)

mobin
mobin

Reputation: 357

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

{% set ns = namespace(found=false) %}
{% for item in items %}
    {% if item.check_something() %}
        {% set ns.found = true %}
    {% endif %}
    * {{ item.title }}
{% endfor %}
Found item having something: {{ ns.found }}

Upvotes: 7

Ivan Lazarev
Ivan Lazarev

Reputation: 1

I realise I'm answering to an old thread. However, I started using Jinja recently and ran into a similar problem: I needed to count the amount of printed rows in nested cycles. My solution was wrapping a counter variable in a class and passing an instance to the template. Similarly, you can use a wrapper class, like so

class VoterStatus(object):
    def __init__(self, status='active'):
        self._status = status

    def set_disabled(self):
        self._status = 'disabled'

    def __str__(self):
        return self._status

Modify your template accordingly

{% for voter in record.voters %}
    {% if user == voter %}
        {% status.set_disabled() %}
    {% endif %}
    {{ status }}  # outputs: 'disabled'
{% endfor %}

Pass a Status class instance to the template for rendering:

tmplt.render(status=VoterStatus(), ...)

...and Bob's your uncle.

Upvotes: 0

Eric
Eric

Reputation: 397

You can use an array/dict like Miguel suggests, but you do not need the do extension per se; you can set a dummy var. I use the following:

{% set glob={} %}

at the top, and then in my code:

{% set _ = glob.update({'disabled':True}) %}

The _ variables is just a dummy, you don't use it afterwards.

Upvotes: 15

Miguel Grinberg
Miguel Grinberg

Reputation: 67502

The easiest way to handle this is to move the logic that sets the disabled variable to your view function and send it down to the template ready to be used. Mixing application logic with presentation is not a good idea, templates should receive the data as digested as possible.

That said, there is an ugly hack that makes what you want possible, shown in the accepted answer to this question.

The solution involves enabling the do extension for Jinja2 and using it to modify a global array. To enable the extension use:

app.jinja_env.add_extension('jinja2.ext.do')

Here is the solution adapted to your example:

{% set disabled = [] %}
{% for voter in record.voters %}
    {% if user == voter %}
        {% do disabled.append(1) %}
    {% endif %}
{% endfor %}
{% if disabled %}
    disabled
{% endif %}

Upvotes: 16

Daniel Chatfield
Daniel Chatfield

Reputation: 2970

By default blocks may not access variables from outer scopes, you can override this by using the scoped modifier like so:

{% for item in list scoped %}
{% endfor %}

See: http://jinja.pocoo.org/docs/templates/#block-nesting-and-scope

Upvotes: 1

Related Questions