我有一个Django SaaS应用程序,用户可以创建自己的Jinja2模板(在一个非常沙盒的环境中,对于那些刚刚被诅咒的人),这些模板被保存到数据库中。我有一个template_type
字段,注意给定模板是“包含”还是“完整模板”(完整模板当然可以包含“包含”)。问题是,用户可以将{% include "foo" %}
放入名为"bar"
的模板中,将{% include "bar" %}
放入"foo"
模板中,从而导致RuntimeError: maximum recursion depth exceeded
类型的情况,对表现不利。
有没有一种很好的方法来处理这种情况,不包括验证regexp(例如,r'\{%\s+include'
)在用户模板创建时检查包含(“确保递归导入永远不会进入数据库,或者你的服务器会崩溃“与我不太相信”。
我开始使用自定义加载程序,它只包含用户的“includes”::
def get_source(self, environment, template):
"""
Returns the source of the template or raises ``TemplateNotFound``.
This loader is for use with an environment which intends to load each
template from a string, since only includes are loaded from here.
"""
try:
template = self.snippets[template]
except KeyError:
raise jinja2.TemplateNotFound(
template, message=u'Snippet "{s}" was not found'.format(s=template)
)
else:
source = template['source']
return (source, None, lambda: True)
这样做的问题在于我基本上无法利用Jinja2的Bytecode Cache,这显然要求所有模板都可用于load(...
电话,反过来调用get_source(...
。
答案 0 :(得分:3)
要解析模板并检查包含,我使用以下代码:
ast = env.parse(template_text)
for each in meta.find_referenced_templates(ast) : # find the (% includes %}