Jinja2:模板内的渲染模板

aka*_*n64 5 python jinja2

是否可以在字符串给出的另一个模板中呈现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到另一个文件,但在这里我不想遵循这种方式.

7yl*_*l4r 5

我没有一个可以轻松测试这些想法的环境,但是我正在用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的文档,以确保没有更好的方法。