【问题标题】:How can I set a (non-global) variable in a jinja context function?如何在 jinja 上下文函数中设置(非全局)变量?
【发布时间】:2017-09-04 16:27:40
【问题描述】:

我想设置变量值,但前提是它们尚未分配并且在本地上下文中。

所以有一个解决办法:

{% 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 上设置一个值也无济于事:

变量
模板局部变量。此列表包含来自父范围以及本地的环境和上下文函数 从模板中修改和导出变量。模板 将在模板评估期间修改此字典,但过滤器和 不允许上下文函数对其进行修改。
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 源代码时并没有真正掌握这一点。

【问题讨论】:

    标签: python jinja2


    【解决方案1】:

    我找到了解决方案,不知何故我一直在解决自己的问题。这并不完全是对“如何在 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 吗?

    【讨论】:

      猜你喜欢
      • 2014-04-01
      • 1970-01-01
      • 2012-04-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-08-20
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多