4

我在 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并搜索 immutable)

4

4 回答 4

13

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

{% for bar in bars %}
    {% if loop.index == 1 %}
        Print me once
    {% endif %}
    Print me every time
{% endfor %}
于 2012-12-19T11:23:08.977 回答
4

我的建议是在 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 的表达式/导入/任何东西都足够强大,你不必对所有东西都使用扩展。

是的,使用这个context.my_flag东西是个坏主意。只有模板才能修改上下文。曾经。

于 2010-07-28T16:36:11.090 回答
1

我会定义一个布尔值和一个宏,然后从那里开始。不是打印变量,而是打印宏的结果,该宏使用 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) %}
于 2010-07-01T15:37:52.930 回答
0

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 宏,其中包含您只想输出一次的文本: macros.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') }}
于 2020-01-19T19:08:55.267 回答