我正在尝试做这样的事情:
{% macro obj_type_1 %}
stuff
{% endmacro %}
{% macro obj_type_2 %}
stuff
{% endmacro %}
{{ (obj|get_type)(obj) }}
Run Code Online (Sandbox Code Playgroud)
在此示例中,get_type是一个将返回的过滤器obj_type_1或obj_type_2- 即要调用的宏的名称obj.我不想标记obj配置输出,因为现在obj在几个模板中用作结构数据,根据上下文使用不同的标记进行渲染.
我知道这里的语法有点折磨,但我认为这是因为我想要做的事情在Jinja模板中不可能立即实现.我试图用模板替换一些if/elif/else废话的一些配置生成代码,但这一点似乎是一个棘手的问题.
您可以创建一个Jinja2过滤器,从当前上下文中获取宏,然后评估宏.过滤器是:
@contextfilter
def call_macro_by_name(context, macro_name, *args, **kwargs):
return context.vars[macro_name](*args, **kwargs)
Run Code Online (Sandbox Code Playgroud)
如果您的应用程序需要,您可以在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())
Run Code Online (Sandbox Code Playgroud)
打印
MyMacro(direct)
MyMacro(indirect)
Run Code Online (Sandbox Code Playgroud)
宏可以通过 import dict 用法简单地调用:
宏.html
{% macro render_foo(value) %}
HELLO {{ value }}!
{% endmacro %}
Run Code Online (Sandbox Code Playgroud)
my_view.html
{% import "macros.html" as my_macros %}
{% set macro_name = 'render_' + dynamic_content %}
{{ my_macros[macro_name]('world') }}
Run Code Online (Sandbox Code Playgroud)
呈现为:
HELLO world!
Run Code Online (Sandbox Code Playgroud)
就个人而言,由于 get_type 用作调度程序,因此将其实现为 jinja 宏(根据 obj 的类型调用专用宏)会更透明。这消除了它返回可调用宏的需要,同时整合了专用宏和指示如何/何时使用它们的逻辑。