假设我在变量X中有实际的jinja模板代码 . 让我们说X的内容是“{}” .
如何在呈现内容的同时显示X?
例如,这不起作用:
{}
因为它只是将其渲染为“{}”而不是some_other_variable的内容 .
我这样做的原因是我有一个网站,其中(可信的)用户可以创建自己可能包含jinja模板代码的帖子 . 视图页面显示这些帖子,但由于上述问题,直接呈现它们,而不是按照我的意愿替换变量 .
我知道它有点晚了:)但是这里有一个解决方案而不会影响模板代码:
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
测试运行:
>>> recursive_render("Hello {{X}}!", dict(X="{{name}}", name="world")) u'Hello world!'
请注意,这不是非常有效,因为必须在每次迭代时从头开始重新分析模板 .
我想到了一个有趣的方法来做到这一点:
设置字典
在它周围缠绕一个DictLoader(但保留对字典的引用)
将带有DictLoader和普通Loader的ChainLoader传递给环境
实现自定义过滤器,将其参数添加到上述字典中
使用 include 指令在当前上下文中调用模板代码
include
没试过,但它可能会奏效!
我找不到一个好的方法来做这个嵌套渲染,但是,我可能会尝试建议一个替代方案:
由于用户创建帖子,我想“{}”实际上是整个帖子的子字符串,也是一个字符串 .
我会做:
X.replace("{{some_other_variable}}", some_other_variable))
然后按正常方式返回{} . 那会满足你想做的吗?
这就是我想到的,使用环境的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)
我找到了一种使用模板文件和环境全局变量的方法 .
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))
render(template, dict(content=post, tags=tags))
哪里 template = env.get_template('index.html')
template = env.get_template('index.html')
创建新过滤器:
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 回答
我知道它有点晚了:)但是这里有一个解决方案而不会影响模板代码:
测试运行:
请注意,这不是非常有效,因为必须在每次迭代时从头开始重新分析模板 .
我想到了一个有趣的方法来做到这一点:
设置字典
在它周围缠绕一个DictLoader(但保留对字典的引用)
将带有DictLoader和普通Loader的ChainLoader传递给环境
实现自定义过滤器,将其参数添加到上述字典中
使用
include
指令在当前上下文中调用模板代码没试过,但它可能会奏效!
我找不到一个好的方法来做这个嵌套渲染,但是,我可能会尝试建议一个替代方案:
由于用户创建帖子,我想“{}”实际上是整个帖子的子字符串,也是一个字符串 .
我会做:
然后按正常方式返回{} . 那会满足你想做的吗?
这就是我想到的,使用环境的finalize选项:
它有点难看,欢迎改进:)
但是它按照OP要求进行递归渲染,并且在输出中没有更多
{{
之前不会停止 .示例会话
编辑:
好的,重构我的渲染功能,功能相同,但有点整洁:
我找到了一种使用模板文件和环境全局变量的方法 .
在这个版本中,你必须将环境全局变量传递给这个函数内部的render函数,并且它自己的函数必须在你的构建函数中 .
向其发送内容的方式是:
render(template, dict(content=post, tags=tags))
哪里
template = env.get_template('index.html')
创建新过滤器:
然后在模板中使用它: