JJIA2:在模板内呈现模板

2022-02-27 00:00:00 python jinja2

问题描述

是否可以在字符串提供的另一个模板内呈现JJIA2模板?例如,我想要字符串

{{ s1 }}

要呈现给

Hello world

给定以下词典作为Template.render的参数:

{ 's1': 'Hello {{ s2 }}', 's2': 'world' }

我知道可以使用include标记将s1的内容分隔到另一个文件,但这里我不想遵循这种方式。


解决方案

我没有轻松测试这些想法的环境,但我正在探索Airflow使用JJJA模板的类似情况。

根据我所能找到的最佳方法是显式地在外部模板中呈现内部模板字符串。为此,您可能需要传递或导入参数词典中的the Template constructor。

以下是一些(未经测试的)代码:

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
)

这远不如您希望的那样干净,因此我们或许可以通过创建custom filter来进一步改进,这样我们就可以这样使用它:

{{ s1|inner_render({"s2":s2}) }}

这里有一个自定义的过滤,我认为可以完成这项工作:

from jinja2 import Template
def inner_render(value, context):
    return Template(value).render(context)

现在,让我们假设我们想要与外部模板相同的上下文,并且-不管怎么样-让我们呈现任意深度的级别N。希望一些示例用法如下所示:

{{ s1|recursive_render }}

{{ s3|recursive_render(2) }}

从我们的自定义过滤获取上下文的一种简单方法是使用contextfilter decorator

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)
现在您可以执行类似s3 = '{{ s1 }}!!!'{{ s3|recursive_render(2) }}应该呈现为Hello world!!!的操作。我想您可以更深入地通过计数括号来检测要呈现的级别数。


看过所有这些之后,我想明确指出这非常令人困惑。

虽然我确实认为我发现在我非常具体的气流使用中需要2个级别的渲染,但我无法想象还有比这更多的级别需要。

如果您正在阅读"这正是我需要的"的想法:无论您尝试做什么,都可能更有说服力。后退一步,考虑到您可能有xy problem,并重新阅读JJJA的文档,以确保没有更好的方法。

相关文章