是否可以在字符串给出的另一个模板中呈现Jinja2模板?例如,我想要字符串
{{ s1 }}
Run Code Online (Sandbox Code Playgroud)
要呈现给
Hello world
Run Code Online (Sandbox Code Playgroud)
给出以下字典作为参数Template.render:
{ 's1': 'Hello {{ s2 }}', 's2': 'world' }
Run Code Online (Sandbox Code Playgroud)
我知道类似的过程可以使用include标记将内容分隔s1到另一个文件,但在这里我不想遵循这种方式.
我没有一个可以轻松测试这些想法的环境,但是我正在用airflow对Jinja模板进行探索。
从我能找到的最好方法中,是在外部模板中显式渲染内部模板字符串。为此,您可能需要在param字典中传递或导入Template构造函数。
这是一些(未经测试的)代码:
from jinja2 import Template
template_string = '{{ Template(s1).render(s2=s2) }}'
outer_template = Template(template_string)
outer_template.render(
s1='Hello {{ s2 }}',
s2='world',
Template=Template
)
Run Code Online (Sandbox Code Playgroud)
这不像您希望的那样干净,因此我们可以通过创建自定义过滤器来进一步处理事情,这样我们就可以像这样使用它:
{{ s1|inner_render({"s2":s2}) }}
Run Code Online (Sandbox Code Playgroud)
这是我认为可以完成此工作的自定义过滤器:
from jinja2 import Template
def inner_render(value, context):
return Template(value).render(context)
Run Code Online (Sandbox Code Playgroud)
现在,我们假设我们想要与外部模板相同的上下文,并且-到底是什么-让我们呈现任意深度的层次N。希望一些示例用法如下所示:
{{ s1|recursive_render }}
{{ s3|recursive_render(2) }}
Run Code Online (Sandbox Code Playgroud)
从自定义过滤器获取上下文的一种简单方法是使用contextfilter装饰器
from jinja2 import Template
from jinja2 import contextfilter
@contextfilter
def recursive_render(context, value, N=1):
if N == 1:
val_to_render = value
else:
val_to_render = recursive_render(context, value, N-1)
return Template(value).render(context)
Run Code Online (Sandbox Code Playgroud)
现在,您可以执行类似操作,s3 = '{{ s1 }}!!!'并{{ s3|recursive_render(2) }}应渲染到Hello world!!!。我想您可能会更深入,并通过计算方括号来检测要渲染的级别数。
在经历了所有这些之后,我想明确指出这是非常令人困惑的。
尽管我确实相信我已经发现在非常特定的气流使用情况下需要2个渲染级别,但是我无法想象需要更多的渲染级别。
如果您正在阅读这种想法,“这正是我需要的”:无论您想做什么,都可以更有雄辩地完成。退后一步,考虑到您可能存在xy问题,然后重新阅读jinja的文档,以确保没有更好的方法。