假设我在变量X中有实际的jinja模板代码。让我们说X的内容是“{{some_other_variable}}”。
如何在呈现内容的同时显示X?
例如,这不起作用:{{X}}
因为它只是将其渲染为“{{some_other_variable}}”而不是some_other_variable的内容。
我这样做的原因是我有一个网站,其中(可信的)用户可以创建自己可能包含jinja模板代码的帖子。视图页面显示这些帖子,但由于上述问题,直接呈现它们,而不是按照我的意愿替换变量。
答案 0 :(得分:6)
我知道它有点晚了:)但这是一个不影响模板代码的解决方案:
gcc
试运行:
import jinja2
def recursive_render(tpl, values):
prev = tpl
while True:
curr = jinja2.Template(prev).render(**values)
if curr != prev:
prev = curr
else:
return curr
请注意,这不是非常有效,因为必须在每次迭代时从头开始重新分析模板。
答案 1 :(得分:2)
我想到了一个有趣的方法:
include
指令在当前上下文中调用模板代码没试过,但它可能会奏效!
答案 2 :(得分:1)
我找不到一个好的方法来做这个嵌套渲染,但是,我可能会尝试建议一个替代方案:
由于用户创建帖子,我想“{{some_other_variable}}”实际上是整个帖子的子字符串,也是一个字符串。
我愿意:
X.replace("{{some_other_variable}}", some_other_variable))
然后按正常情况返回{{X}}。那会满足你想要做的吗?
答案 3 :(得分:0)
这就是我提出的,使用环境的finalize选项:
def render (tpl, args):
scope = {}
scope['env'] = jinja2.Environment (finalize=lambda x: scope['env'].from_string (x).render (**args) if isinstance(x, str) and '{{' in x else x)
scope['env'].filters['q'] = lambda value: re.sub (r'"', r'\\"', value)
return scope['env'].from_string (tpl).render (**args)
这有点难看,所以欢迎改进:)
但它确实是OP要求的递归渲染,并且在输出中不再有{{
之前不会停止。
示例会话
>>> import jinja2
>>> def render (tpl, args):
... scope = {}
... scope['env'] = jinja2.Environment (finalize=lambda x: scope['env'].from_string (x).render (**args) if isinstance(x, str) and '{{' in x else x)
... scope['env'].filters['q'] = lambda value: re.sub (r'"', r'\\"', value)
... return scope['env'].from_string (tpl).render (**args)
...
>>> render("this {{ outer_var }} wokring!", {"outer_var":"{{ inner_var }}", "inner_var":"{{ final_step }}", "final_step":"is"})
u'this is wokring!'
编辑:
好的,重构我的渲染功能,功能相同,但有点整洁:
def render (tpl, args):
@jinja2.environmentfunction
def finalize (env, value):
if isinstance(value, (str, unicode)) and '{{' in value:
return env.from_string (value).render (args)
return value
env = jinja2.Environment (finalize=finalize)
env.filters['q'] = lambda value: re.sub (r'"', r'\\"', value)
return env.from_string (tpl).render (args)
答案 4 :(得分:0)
我找到了一种处理模板文件和环境全局变量的方法。
def render(template, values):
prev = template.render(**values)
while True:
curr = Template(prev).render(siteinfo=config, menus=menus, blended_header=header, authors=authors, buildinfo=buildinfo, **values)
if curr != prev:
prev = curr
else:
return curr
在这个版本中,你必须将环境全局变量传递给这个函数内部的render函数,并且它自己的函数必须在你的构建函数中。
向其发送内容的方式是:render(template, dict(content=post, tags=tags))
其中template = env.get_template('index.html')
答案 5 :(得分:0)
创建新过滤器:
from jinja2 import contextfilter, Markup
@contextfilter
def subrender_filter(context, value):
_template = context.eval_ctx.environment.from_string(value)
result = _template.render(**context)
if context.eval_ctx.autoescape:
result = Markup(result)
return result
env = Environment()
env.filters['subrender'] = subrender_filter
然后在模板中使用它:
{{ "Hello, {{name}}"|subrender }}
答案 6 :(得分:0)
我建议将X设为宏。
import jinja2
tpl = '''
{% macro X(name) -%}
{{name}}
{%- endmacro %}
Hello {{ X('world') }}!
'''
jinja2.Template(tpl).render()