8

我正在尝试做这样的事情:

{% macro obj_type_1 %}
stuff
{% endmacro %}
{% macro obj_type_2 %}
stuff
{% endmacro %}

{{ (obj|get_type)(obj) }}

在这个例子中,get_type是一个过滤器,它会返回obj_type_1obj_type_2- 即要调用的宏的名称obj。我不想obj用配置输出进行标记,因为现在obj在多个模板中用作结构数据,根据上下文使用不同的标记呈现。

我知道这里的语法有点受折磨,但我认为那是因为我想做的事情在 Jinja 模板中无法立即实现。我正在尝试用模板替换某些配置生成代码中的 if/elif/else 废话,但这似乎是一个症结所在。

4

3 回答 3

10

您可以创建一个 Jinja2 过滤器,它从当前上下文中获取宏,然后评估宏。过滤器是:

@contextfilter
def call_macro_by_name(context, macro_name, *args, **kwargs):
    return context.vars[macro_name](*args, **kwargs)

如果您的应用程序需要,您可以在 context.vars 中查找宏之前对 macro_name 执行字符串操作。

这是一个完整的例子:

#!/usr/bin/env python
from jinja2 import Environment, contextfilter

@contextfilter
def call_macro_by_name(context, macro_name, *args, **kwargs):
    return context.vars[macro_name](*args, **kwargs)

template_string = """\
{%- macro MyMacro(item) %}MyMacro({{ item }}){% endmacro -%}
{{ MyMacro('direct') }}
{{ 'MyMacro' | macro('indirect') }}
"""

env = Environment()
env.filters['macro'] = call_macro_by_name
template = env.from_string(template_string)
print(template.render())

哪个打印

MyMacro(direct)
MyMacro(indirect)
于 2014-07-03T12:12:01.967 回答
4

可以通过 import dict 用法简单地调用宏:

宏.html

{% macro render_foo(value) %}
HELLO {{ value }}!
{% endmacro %}

my_view.html

{% import "macros.html" as my_macros %}

{% set macro_name = 'render_' + dynamic_content %}
{{ my_macros[macro_name]('world') }}

呈现为:

HELLO world!
于 2016-04-12T12:54:07.220 回答
0

就个人而言,由于 get_type 用作调度程序,因此将其实现为 jinja 宏会更透明,该宏会根据 obj 的类型调用专门的宏。这消除了它返回可调用宏的需要,同时整合了专用宏和指示如何/何时使用它们的逻辑。

于 2012-05-17T21:59:29.657 回答