Can a Jinja variable's scope extend beyond in an inner block?

后端 未结 8 835
夕颜
夕颜 2020-11-27 06:07

I have the following Jinja template:

{% set mybool = False %}
{% for thing in things %}
    
    {%
相关标签:
8条回答
  • 2020-11-27 06:33

    You can solve your problem using this hack (without extensions):

    import jinja2
    
    env = jinja2.Environment()
    print env.from_string("""
    {% set mybool = [False] %}
    {% for thing in things %}
        <div class='indent1'>
            <ul>
                {% if current_user %}
                  {% if current_user.username == thing['created_by']['username'] %}
                    {% set _ = mybool.append(not mybool.pop()) %}
                    <li>mybool: {{ mybool[0] }}</li> <!-- prints True -->
                    <li><a href='#'>Edit</a></li>
                  {% endif %}
                {% endif %}
                <li>Flag</li>
            </ul>
        </div>
        <hr />
    {% endfor %}
    
    {% if not mybool[0] %}
        <!-- always prints this -->
        <p>mybool is false!</p>
    {% else %}
      <p>mybool is true!</p>
    {% endif %}
    """).render(current_user={'username':'me'},things=[{'created_by':{'username':'me'}},{'created_by':{'username':'you'}}])
    
    0 讨论(0)
  • 2020-11-27 06:37

    One way around this limitation is to enable the "do" expression-statement extension and use an array instead of boolean:

    {% set exists = [] %}
    {% for i in range(5) %}
          {% if True %}
              {% do exists.append(1) %}
          {% endif %}
    {% endfor %}
    {% if exists %}
        <!-- exists is true -->
    {% endif %}
    

    To enable Jinja's "do" expression-statement extension: e = jinja2.Environment(extensions=["jinja2.ext.do",])

    0 讨论(0)
  • 2020-11-27 06:39

    Answer to a related question: I wanted to have a global counter of the number of times I entered a certain if-block in the template, and ended up with the below.

    At the top of the template:

    {% set counter = ['1'] %}
    

    In the if-block I want to count:

    {% if counter.append('1') %}{% endif %}
    

    When displaying the count:

    {{ counter|length }}
    

    The string '1' can be replaced with any string or digit, I believe. It is still a hack, but not a very large one.

    0 讨论(0)
  • 2020-11-27 06:41

    Found this great article that describes a little hack. It's not possible to change value of a jinja variable in a different scope, but it's possible to modify a global dictionary values:

    # works because dictionary pointer cannot change, but entries can 
    
    {% set users = ['alice','bob','eve'] %} 
    {% set foundUser = { 'flag': False } %} 
    
    initial-check-on-global-foundUser: 
      cmd.run: 
        name: echo initial foundUser = {{foundUser.flag}} 
    
    {% for user in users %} 
    {%- if user == "bob" %} 
    {%-   if foundUser.update({'flag':True}) %}{%- endif %} 
    {%- endif %} 
    echo-for-{{user}}: 
      cmd.run: 
        name: echo my name is {{user}}, has bob been found? {{foundUser.flag}} 
    {% endfor %} 
    
    final-check-on-global-foundUser: 
      cmd.run: 
        name: echo final foundUser = {{foundUser.flag}}
    

    I've also found very helpful this syntax to set the value without actually using set:

    {%-   if foundUser.update({'flag':True}) %}{%- endif %} 
    

    It actually checks the result of an update operation on a dictionary (note to self).

    0 讨论(0)
  • 2020-11-27 06:44

    Here's the general case for anyone wanting to use the namespace() object to have a variable persist outside of a for loop.

    {% set accumulator = namespace(total=0) %}
    {% for i in range(0,3) %}
        {% set accumulator.total = i + accumulator.total %}
        {{accumulator.total}}
     {% endfor %}`          {# 0 1 3 #}
     {{accumulator.total}}  {# 3 (accumulator.total persisted past the end of the loop) #}
    
    0 讨论(0)
  • 2020-11-27 06:46

    Update 2018

    As of Jinja 2.10 (8th Nov 2017) there is a namespace() object to address this particular problem. See the official Assignments documentation for more details and an example; the class documentation then illustrates how to assign several values to a namespace.

    0 讨论(0)
提交回复
热议问题