Jinja 变量的范围可以扩展到内部块之外吗?

发布于 2024-10-15 13:36:33 字数 1418 浏览 2 评论 0原文

我有以下 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 语句中使用它?

编辑

我发现一些建议(仅正确缓存的页面视图),但它们似乎没有工作。也许它们在 Jinja2 中已被弃用...

下面提供了编辑

解决方案。我仍然很好奇为什么上面的建议不起作用。有谁确切知道它们已被弃用?

I have the following Jinja template:

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

If the condition is met in the for loop, I'd like to change mybool to true so I can display mybool is true! below. However, it looks like the scope of the inner mybool is limited to the if statement, so the desired mybool is never set.

How can I set the "global" mybool so I can use it in the last if statement?

EDIT

I've found some suggestions (only the cached page views correctly), but they don't seem to work. Perhaps they're deprecated in Jinja2...

EDIT

Solution provided below. I am still curious why the suggestions above do not work though. Does anyone know for sure that they were deprecated?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

何止钟意 2024-10-22 13:36:33

解决此限制的一种方法是启用 "do" 表达式语句扩展 并改用数组of boolean:

{% 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",])

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",])

残月升风 2024-10-22 13:36:33

对于想要使用 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) #}

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) #}
救星 2024-10-22 13:36:33

回答相关问题:我想要一个全局计数器,记录我在模板中输入某个 if 块的次数,结果如下。

在模板的顶部:

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

在 if 块中我想计数:

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

显示计数时:

{{ counter|length }}

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

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.

放飞的风筝 2024-10-22 13:36:33

2018 年更新

自 Jinja 2.10 起(2017 年 11 月 8 日)有一个 namespace() 对象可以解决这个特定问题。有关更多详细信息,请参阅官方作业文档一个例子; class 文档然后说明了如何分配多个命名空间的值。

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.

少女七分熟 2024-10-22 13:36:33

您可以使用此技巧解决您的问题(无需扩展):

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'}}])

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'}}])
(り薆情海 2024-10-22 13:36:33

当编写 contextfunction() 或类似的东西时,您可能已经注意到上下文试图阻止您修改它。

如果您已设法使用内部上下文 API 修改上下文,您可能会注意到上下文中的更改在模板中似乎不可见。原因是出于性能原因,Jinja 仅使用上下文作为模板变量的主要数据源。

如果要修改上下文,请编写一个返回变量的函数,而不是可以使用 set 分配给变量:

{% set comments = get_latest_comments() %}

来源

When writing a contextfunction() or something similar you may have noticed that the context tries to stop you from modifying it.

If you have managed to modify the context by using an internal context API you may have noticed that changes in the context don’t seem to be visible in the template. The reason for this is that Jinja uses the context only as primary data source for template variables for performance reasons.

If you want to modify the context write a function that returns a variable instead that one can assign to a variable by using set:

{% set comments = get_latest_comments() %}

Source

梦中的蝴蝶 2024-10-22 13:36:33

需要从列表(objects_from_db)中查找对象(object)中的最大条目数,

由于 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] %}

希望这可以帮助其他试图弄清楚同样问题的人。

Had a need to find the max num of entries in an object (object) from a list (objects_from_db),

This did not work for reasons known in jinja2 and variable scope.

 {% set maxlength = 0 %}
 {% for object in objects_from_db %}
     {% set ilen = object.entries | length %}
     {% if maxlength < ilen %}
         {% set maxlength = ilen %}
     {% endif %}
 {% endfor %}

Here's what works:

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

Hope this helps someone else trying to figure out the same.

黎夕旧梦 2024-10-22 13:36:33

发现这个很棒的 文章 描述了一个小技巧。不可能在不同的范围内更改 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 %} 

它实际上检查字典上更新操作的结果(自我注释)。

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).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文