【问题标题】:How to make sure a Jinja custom tag only outputs once?如何确保 Jinja 自定义标签只输出一次?
【发布时间】:2010-07-01 15:16:45
【问题描述】:

我在 Jinja2 中有一个自定义标签,我只想在第一次调用它时输出一些东西。所以说我有以下模板:

1. {% only_once %}
2. {% only_once %}
3. {% only_once %}

我希望输出是:

1. "I only get printed once!"
2.
3.

我猜最好的方法是在模板的上下文中设置一个标志来跟踪我是否已经打印了一些东西。这是一个代码示例,但这对吗?

class OnlyOnceExtension(Extension):
    tags = set(['only_once'])

    @contextfunction
    def parse(self, context, parser):
        if hasattr(context, 'my_flag') and context.my_flag:
            return Output("")
        else:
            return Output("I only get printed once!")

正确吗?我读了一些关于上下文是不可变的东西,所以这不起作用吗? (参见http://jinja.pocoo.org/2/documentation/api 并搜索不可变)

【问题讨论】:

    标签: python jinja2


    【解决方案1】:

    如果你想纯粹用 Jinja 来做,你可以用这种方式检查 loop.index 变量,

    {% for bar in bars %}
        {% if loop.index == 1 %}
            Print me once
        {% endif %}
        Print me every time
    {% endfor %}
    

    【讨论】:

    • 您的解决方案更有意义。我遇到了类似的问题,但现在解决了。谢谢你的伙伴。
    【解决方案2】:

    我的建议是在 Python 代码中实现:

    class OnlyOnce(object):
        def __init__(self, data):
            self.data = data
            self.printed = False
    
        def __str__(self):
            if self.printed is False:
                self.printed = True
                return self.data
            return ''
    

    在您的 Python 代码中创建一个OnlyOnce 实例并将其传递给模板,然后每次您要使用它时,只需使用{{ only_once }}

    我注意到很多使用 Jinja 的人的一件事是,他们希望以 Django 式的方式做事,即编写扩展程序。但是 Jinja 的表达式/导入/whatever 足够强大,您不必对所有内容都使用扩展。

    是的,使用context.my_flag 是个坏主意。只有模板才能修改上下文。 永远。

    【讨论】:

    • 我希望我能把这个答案变成一个关于 StackOverflow 的新问题,供新手们参考,哈哈
    • 我必须对此再发表评论...无论谁理解这个答案,都将具备首先克服这个问题的技能。这对社区有何帮助?看起来这个答案对于程序员来说是一个更高维度的思想。我们必须假设读者完全理解面向对象编程的四个原则吗?如果我们不做这个假设,你用什么原则来优化最初的尝试?
    【解决方案3】:

    我会定义一个布尔值和一个宏,然后从那里开始。不是打印变量,而是打印宏的结果,该宏使用 if 语句和布尔值来决定是否应该打印。因此,您会得到以下信息:

    {{ set was_printed = false }}
    {% macro print_once(to_print) %}
        {% if was_printed is sameas false %}
            {{ to_print }}
            {% set was_printed = true %}
        {% endif %}
    {% endmacro %}
    1. {% print_once(only_once) %}
    2. {% print_once(only_once) %}
    3. {% print_once(only_once) %}
    

    【讨论】:

    • 我尝试使用这个宏,但它的代码无效,TemplateSyntaxError: expected token 'end of print statement', got 'was_printed'
    • 第一行必须是{% set was_printed = false %}
    【解决方案4】:

    Jinja 并不总是重新计算宏,因此设置宏变量不会阻止值被创建两次。公认的解决方案有效,但它要求您在烧瓶视图级别对对象进行硬编码。 我通过创建一个自定义 jinja 过滤器解决了这个问题,每个请求只会返回一次值。

    过滤器:

    from flask import g    
    
    def onetime(val, atr):
        """
        this filter will return the given value only once per request
    
        :param val: the value to return 1 time
        :type val: str
        :param atr: the attribute to remember this value by
        :type atr: str
        :return: returns True for this attribute once per request
        :rtype: str
        """
        # has this attribute been set for this request?
        if getattr(g, atr, False):
            # the value has already been returned for this request
            return ""
        # set the flag
        setattr(g, atr, True)
        # return the value, this is the first call
        return val
    

    将过滤器添加到您的烧瓶应用中

    app.jinja_env.filters['onetime'] = onetime
    

    创建一个 jinja 宏,其中包含您只想输出一次的文本: 宏.html

    {% macro my_macro() %}
    This text should only be created once
    {% endmacro %}
    

    并使用它:

    {{ my_macro() | onetime('a_name') }}
    {{ my_macro() | onetime('a_name') }}
    {{ my_macro() | onetime('a_name') }}
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-01-29
      • 2019-11-12
      • 2017-09-27
      • 1970-01-01
      • 2013-12-09
      • 1970-01-01
      • 2020-12-04
      • 1970-01-01
      相关资源
      最近更新 更多