如何防止Jinja2模板中的循环{%include%}调用

时间:2012-11-13 05:30:08

标签: python django template-engine jinja2 circular-reference

我有一个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(...

1 个答案:

答案 0 :(得分:3)

要解析模板并检查包含,我使用以下代码:

    ast = env.parse(template_text)
    for each in meta.find_referenced_templates(ast) :        # find the (% includes %}