我有以下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 %}
如果for
循环中符合条件,我想将mybool
更改为true,以便我可以在下面显示mybool is true!
。但是,看起来内部mybool
的范围仅限于if
语句,因此永远不会设置所需的 mybool
。
如何设置“全局”mybool
,以便我可以在上一个if
语句中使用它?
修改
我找到some suggestions(只有正确的缓存页面浏览量),但它们似乎不起作用。也许他们在Jinja2中被弃用了......
修改
下面提供的解决方案。我仍然很好奇为什么上述建议不起作用。有谁知道他们被弃用了吗?
答案 0 :(得分:46)
解决此限制的一种方法是启用"do" expression-statement extension并使用数组而不是布尔值:
{% set exists = [] %}
{% for i in range(5) %}
{% if True %}
{% do exists.append(1) %}
{% endif %}
{% endfor %}
{% if exists %}
<!-- exists is true -->
{% endif %}
启用Jinja的“do”表达式语句扩展名:e = jinja2.Environment(extensions=["jinja2.ext.do",])
答案 1 :(得分:14)
回答相关问题:我希望得到一个全局计数器,其中包含我在模板中输入某个if-block的次数,最后是以下结果。
位于模板顶部:
{% set counter = ['1'] %}
在if-block中我想算一下:
{% if counter.append('1') %}{% endif %}
显示计数时:
{{ counter|length }}
我相信字符串'1'
可以替换为任何字符串或数字。它仍然是一个黑客,但不是一个非常大的。
答案 2 :(得分: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'}}])
答案 3 :(得分:5)
更新2018年
自Jinja 2.10(2017年11月8日)起,有一个namespace()
对象来解决这个特殊问题。有关详细信息和示例,请参阅官方Assignments documentation;然后class
documentation说明了如何为命名空间分配多个值。
答案 4 :(得分:4)
在编写contextfunction()
或类似内容时,您可能已经注意到上下文试图阻止您修改它。
如果您已设法使用内部上下文API修改上下文,您可能已经注意到上下文中的更改似乎在模板中不可见。原因是出于性能原因,Jinja
仅将上下文用作模板变量的主要数据源。
如果要修改上下文,请编写一个返回变量的函数,而不是可以使用set赋值给变量:
{% set comments = get_latest_comments() %}
答案 5 :(得分:3)
是否需要从列表中找到对象(对象)中的最大条目数(objects_from_db),
由于jinja2和变量范围中已知的原因,这不起作用。
{% set maxlength = 0 %}
{% for object in objects_from_db %}
{% set ilen = object.entries | length %}
{% if maxlength < ilen %}
{% set maxlength = ilen %}
{% endif %}
{% endfor %}
以下是有效的:
{% set mlength = [0]%}
{% for object in objects_from_db %}
{% set ilen = object.entries | length %}
{% if mlength[0] < ilen %}
{% set _ = mlength.pop() %}
{% set _ = mlength.append(ilen)%}
{% endif %}
{% endfor %}
{% set maxlength = mlength[0] %}
希望这有助于其他人试图找出相同的东西。
答案 6 :(得分:0)
发现了一个很棒的article,它描述了一些小技巧。不可能在其他范围内更改jinja变量的值,但可以修改全局字典值:
# 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}}
我还发现这种语法在不实际使用set
的情况下设置值非常有用:
{%- if foundUser.update({'flag':True}) %}{%- endif %}
它实际上检查字典上update
操作的结果(自我注释)。
答案 7 :(得分:0)
这是所有想要使用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) #}