如何在jinja上下文函数中设置(非全局)变量?

时间:2017-09-04 16:27:40

标签: python jinja2

我想设置变量值,但仅限于它们尚未分配且位于本地上下文中。

所以有一个解决方案:

{% with x=( x | default(1)) %}
    {{ x }}
{% endwith %}

{% with x=2 %}
    {% with x=( x | default(1)) %}
        {{ x }}
    {% endwith %}
{% endwith %}

这很好用,但它有很多文字。我有很多情况,我没有一个,但最多有20个变量被设置,然后调用一个宏,或者这些值包含一个模板。

编写所有这些默认条件只是一团糟并引发错误。所以我希望能够在例如当前环境中设置一个值。在上下文函数中。但是,如果我尝试以下内容:

@contextfunction
def defaults(ctx, **vals):
    for k,v in vals.iteritems():
      if k not in ctx:
          ctx[k] = v

我得到一个例外:

  

TypeError:'Context'对象不支持项目分配

尝试在ctx.vars上设置一个值也无济于事:

  


  模板局部变量。此列表包含父作用域和本地的环境和上下文功能   从模板中修改和导出变量。模板   将在模板评估期间修改此dict,但过滤和   上下文函数不允许修改它   http://jinja.pocoo.org/docs/2.9/api/#jinja2.Context.vars

我试过

@contextfunction
def defaults(ctx, **vals):
    for k,v in vals.iteritems():
         if k not in ctx.vars:
             ctx.vars[k] = v

它没有例外,但似乎没有将值分配给上下文。

我知道我可以写入全球背景,但这不是我想做的,因为它会产生副作用。

是否有可能仅获取当前上下文并为其设置值?我没有找到任何关于它的说明以及如何做到这一点我并没有真正理解这一点来阅读jinja来源。

1 个答案:

答案 0 :(得分:0)

我找到了一个解决方案,不知怎的,我一直在解决自己的问题。这不是"我如何在jinja上下文函数中设置(非全局)变量的答案?" ,但它解决了问题。

我写了一个jinja扩展,允许一个简单的"默认"标记:

from jinja2 import nodes
from jinja2.ext import Extension

"""
    DefaultExtension
    ~~~~~~~~~~~~~~~~
    Very simple jinja extension that allows for the following 

    {% set x=(x | default(1)) %}
    {% set y=(y | default(2)) %}

    to be written as 

    {% default x=1, y=2 %}

    :copyright: (c) 2017 by the Roman Seidl
    :license: BSD
"""

class DefaultExtension(Extension):
    # a set of names that trigger the extension.
    tags = set(['default'])

    def parse(self, parser):
        #just dump the tag
        lineno = next(parser.stream).lineno

        #parse through assignments (similar to parser.parse_with)
        assignments = []
        while parser.stream.current.type != 'block_end':
            lineno = parser.stream.current.lineno
            if assignments:
                parser.stream.expect('comma')
            target = parser.parse_assign_target()
            parser.stream.expect('assign')
            expr = (parser.parse_expression())
            #consruct a 'default' filter
            filter = nodes.Filter(nodes.Name(target.name, 'load'), 'default', [expr], [], None, None, lineno=lineno)
            #produce an assignment with this filter as value
            assignment = nodes.Assign(target, filter, lineno=lineno)
            assignments.append(assignment)
      return assignments

我只需将其添加到我的应用中:

app.jinja_env.add_extension(DefaultExtension)
虽然我必须承认我还没有对它进行过彻底的测试,但它的效果非常好。

有人认为我应该把它提交给jinja吗?