Jinja变量的范围是否可以扩展到内部块?

Mat*_*ris 57 variables templates scope jinja2

我有以下Jinja模板:

{% set mybool = False %}
{% for thing in things %}
    <div class='indent1'>
        <ul>
            {% if current_user %}
              {% if current_user.username == thing['created_by']['username'] %}
                {% set mybool = True %}
                <li>mybool: {{ mybool }}</li> <!-- prints True -->
                <li><a href='#'>Edit</a></li>
              {% endif %}
            {% endif %}
            <li>Flag</li>
        </ul>
    </div>
    <hr />
{% endfor %}

{% if not mybool %}
    <!-- always prints this -->
    <p>mybool is false!</p>
{% else %}
  <p>mybool is true!</p>
{% endif %}
Run Code Online (Sandbox Code Playgroud)

如果在for循环中满足条件,我想mybool改为true,所以我可以mybool is true!在下面显示.但是,看起来内部的范围mybool仅限于if语句,因此永远不会设置所需的 mybool范围.

如何设置"全局",mybool以便我可以在最后一个if语句中使用它?

编辑

我发现了一些建议(只有正确的缓存页面视图),但它们似乎不起作用.也许他们在Jinja2中被弃用了......

编辑

解决方案如下.我仍然很好奇为什么上述建议不起作用.有谁知道他们被弃用了吗?

Gar*_*ett 47

解决此限制的一种方法是启用"do"表达式语句扩展并使用数组而不是布尔值:

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

要启用Jinja的"do"表达式语句扩展: e = jinja2.Environment(extensions=["jinja2.ext.do",])

  • 不需要这个"do"表达式语句.将表达式放在if条件中:)`{%if exists.append(1)%} {%endif%}` (22认同)
  • @ schettino72当你没有`do`表达式时,甚至有一种更短的方法:`{%set _ = exists.append(1)%}`.这是[DebOps](http://debops.org/)项目(Ansible stuff)中的常见做法. (11认同)

God*_*ith 15

回答相关问题:我希望有一个全局计数器,表示我在模板中输入某个if-block的次数,最后得到了以下结果.

在模板的顶部:

{% set counter = ['1'] %}
Run Code Online (Sandbox Code Playgroud)

在if-block中我想要计算:

{% if counter.append('1') %}{% endif %}
Run Code Online (Sandbox Code Playgroud)

显示计数时:

{{ counter|length }}
Run Code Online (Sandbox Code Playgroud)

'1'我相信,字符串可以替换为任何字符串或数字.它仍然是一个黑客,但不是一个非常大的.


Jen*_*ens 9

更新2018年

从Jinja 2.10(2017年11月8日)开始,有一个namespace()目标是解决这个特殊问题.有关详细信息和示例,请参阅官方作业文档 ; 然后,class文档说明了如何为命名空间分配多个值.

  • @jens 是的,但是一个简单的例子可以使这个答案更好,并确保当链接失效时它仍然有用 (2认同)

Alv*_*tes 8

你可以使用这个hack解决你的问题(没有扩展):

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'}}])
Run Code Online (Sandbox Code Playgroud)


jef*_*ack 7

这是任何想要使用namespace()对象在for循环外持久化变量的人的一般情况。

{% 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) #}
Run Code Online (Sandbox Code Playgroud)