假设我有以下模板:
<!DOCTYPE html>
<html>
{{ var1 }}
{% if var1 and var2 %}
<span>some text</span>
{% endif %}
{{ var2 }}
</html>
当我使用var1=3
作为上下文进行渲染时,它会生成此输出:
<!DOCTYPE html>
<html>
3
{% if 3 and var2 %}
<span>some text</span>
{% endif %}
{{ var2 }}
</html>
当我使用var2=5
作为上下文再次渲染第一个渲染的输出时,输出为:
<!DOCTYPE html>
<html>
3
<span>some text</span>
5
</html>
问题是大多数模板引擎会将上下文中缺少的变量评估为空字符串。这些都是在假设只有一个渲染的情况下构建的。
我知道jinja2可以用这种方法做到这一点:Multiple renders of jinja2 templates?
但它在if
语句中不起作用,它只适用于单个变量。
任何流行的模板库是否都具有我描述的渲染模式?马可?元史?别的什么?也许这是一个非python模板引擎吗?
答案 0 :(得分:5)
我所知道的任何模板语言都不存在此功能。您最好的选择是:
我认为你在这里有几个选项,其中一些来自here,但其中没有一个涉及模板系统的内置功能。基本上,这里的目标是让渲染输出包含再次呈现的模板标记。
正如我所看到的,最简单的方法是使用templatetag
模板标签或编写自己做类似的事情,并负责转义。
如果您可靠地首先呈现var1
而第二次var2
呈现:
<!DOCTYPE html>
<html>
{{ var1 }}
{% templatetag openblock %} if {{ var1 }} and var2 {% templatetag closeblock %}
<span>some text</span>
{% templatetag openblock %} endif {% templatetag closeblock %}
{% templatetag openvariable %} var2 {% templatetag closevariable %}
</html>
第一次渲染时,你会得到:
<!DOCTYPE html>
<html>
{{ 3 }}
{% if 3 and var2 %}
<span>some text</span>
{% endif %}
{{ var2 }}
</html>
在第二次渲染时,会产生所需的输出。
显然,不断编写多层{% templatetag %}
会是一个巨大的痛苦,所以我建议你编写自己的递归模板标签,为你解决这个问题,可能还有一个参数指明如何你需要多层嵌套,然后显然是输入本身的一个参数。关于这一点的好处是,如果你只需要一层嵌套,只需输出模板标签,输入就可以了,
基本上,通过递归地使用此自定义模板标记输出,您可以非常轻松地实现尽可能多的嵌套层。假设标记实现为{% t <layers of nesting> <input> %}
:
Initial template: {% t 2 "{{ var2 }}" %} First rendering: {% t 1 "{{ var2 }}" %} Second rendering: {{ var2 }} Final rendering: 5
现在,对于某些更复杂的标记,例如{% if %}
,这肯定会更加困难,特别是如果在您的示例中,您在单个if语句中需要多层渲染。你可能最好在这里拆分你的if语句,这样你就可以有更清晰的渲染分离。以下示例假定{% t %}
标记的实现,它是{% t %}
/ {% endt %}
组合:
初始HTML:
{% if var1 %}
{% t 1 %}
{% if var2 %}
<span>some text</span>
{% endif %}
{% endt %}
{% endif %}
首先渲染:
{# Note that the first if statement has been evaluated and is gone #}
{% if var2 %}
<span>some text</span>
{% endif %}
最终呈现:
<span>some text</span>
答案 1 :(得分:0)
在这里重提一个老问题——我最近想做这个,发现原来的答案过于复杂。这是相同答案的更简单版本。 TLDR;使用扩展程序。
为此做一个扩展是相当简单的。这是我用来部分呈现模板的一个扩展版本。我使用自定义标签 preserve
和 endpreserve
来分隔我不想在第一遍呈现的块。
此模板的渲染结果仅用于创建另一个模板,该模板可以在第二次传递期间具有未渲染的变量等。
用法。
text = ...
pass_1 = Template(text, extensions=[PreserveExtension])
result_1 = pass_1.render(...)
pass_2 = Template(pass_1)
final_render = pass_2.render(...)
这是扩展名。
class PreserveExtension(Extension):
"""
Extensions ignores jinja templates between tags.
NOTE: Preserved template spacing is slightly modified.
Example Input:
this is plain text
{%- preserve %}
this is plain text
{{ a }}
{%- if b %}{{ b }}{% endif -%}
{% for i in c -%}
{{ i }}
{%- endfor %}
{%- endpreserve %}
Example Output:
this is plain text
this is plain text
{{ a }}{%- if b %} {{ b }} {% endif -%}
{% for i in c -%}
{{ i }}{%- endfor %}
"""
tags = {"preserve"}
def parse(self, parser: Parser):
lineno = parser.stream.current.lineno
parser.parse_expression()
parser.stream.skip()
body = []
raw = []
def flush():
nonlocal raw
nonlocal body
node = nodes.TemplateData(''.join(raw))
body.append(node)
raw = []
while True:
t: Token = next(parser.stream)
if t.lineno != lineno:
flush()
lineno = t.lineno
test = t.test('name:endpreserve')
if test:
raw.pop(-1)
break
if raw and not raw[-1].endswith('\n'):
raw.append(' ')
raw.append(t.value)
if raw:
flush()
return body