Jinja2:在循环内更改变量的值


77

我想在循环内更改在循环外声明的变量的值。但是总是在变化,它将初始值保持在循环之外。

{% set foo = False %}

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

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

这将呈现:

Ok(1)!

因此,到目前为止发现的唯一(坏)解决方案是:

{% set foo = [] %}

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

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

这将呈现:

Ok(1)!
Ok(2)!

但是,它非常丑陋!还有另一个更优雅的解决方案吗?


3
我认为没有其他办法。也许您可以重组代码,从而无需设置变量。
亚历克斯·莫雷加

2
+1的问题,因为它成为我的答案:)
Glen Swift 2013年

1
@Shankar Cabus:很好的问题。这可能应该归类于Jinja Annoyances
dreftymac

我认为这是重复的问题:stackoverflow.com/questions/7537439/…stackoverflow.com/questions/4870346/…(只是开始,无法标记问题)您可以使用Pashka的方法,并对其jinja2.ext.do进行清理一点点
Gerardo Roza

我发现此代码是无法在salt + jinja中使用的变通方法构造的唯一方法:somelist | map(format)| join
Martin

Answers:


77

也尝试基于字典的方法。似乎不太丑。

{% 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 %}

这也会呈现:

Ok(1)!
Ok(2)!

8
仍然很丑陋,但是行得通。我很惊讶jinja2没有Pythonic的方法。
kramer65 2015年

1
绝对干净一点,尤其是在您需要多个变量的情况下
Ade Miller

1
TLDR,是否set vars仅在for循环中不起作用?
ThorSummoner

3
@ kramer65:解决方案似乎正在起作用:github.com/pallets/jinja/pull/684 ; github.com/pallets/jinja/pull/676
迈克尔·

@ThorSummoner看起来像。我一直听到很多人赞美python。他们也只是用水煮饭。
Toskan

43

如文档中所述:

请注意,循环中的分配将在迭代结束时清除,并且不会超出循环范围。

但从2.10版开始,您可以使用名称空间:

    {% 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 %}

2
您在哪里说namespace(foo=false)False中的小写f是jinja2口语,还是您想当False,因为python需要布尔值?
malan88 '18年

4
小写的false是jinja约定的一部分:“ The special constants true, false, and none are indeed lowercase. Because that caused confusion in the past, (True used to expand to an undefined variable that was considered false), all three can now also be written in title case (True, False, and None). However, for consistency, (all Jinja identifiers are lowercase) you should use the lowercase versions.
Omer

0

您可以这样做来清理模板代码

{% 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 %}

并在服务器代码中使用

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)

这可以概括为以下几点

{{ 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 %}

并在服务器代码中使用

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)
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.