如何在Jinja2模板中间接调用宏?

时间:2012-05-17 04:30:33

标签: python jinja2

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

{% 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废话的一些配置生成代码,但这一点似乎是一个棘手的问题。

3 个答案:

答案 0 :(得分:8)

您可以创建一个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)

答案 1 :(得分:2)

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

<强> macros.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!

答案 2 :(得分:0)

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