/ / Como posso evitar chamadas circulares {% include%} em modelos Jinja2 - python, django, template-engine, jinja2, referência circular

Como posso evitar chamadas circulares {% include%} nos modelos Jinja2 - python, django, template-engine, jinja2, referência circular

Eu tenho um aplicativo Django SaaS com usuários que criam seus próprios modelos Jinja2 (em um ambiente extraordinariamente seguro, para aqueles que apenas se encolheram), que são salvos em um banco de dados. eu tenho um template_type campo, observando se um determinado modelo é um "incluir" ou um "modelo completo" (um modelo completo pode incluir "inclui"). O problema é que um usuário poderia colocar {% include "foo" %} em um modelo chamado "bar"e {% include "bar" %} no "foo" modelo, causando um RuntimeError: maximum recursion depth exceeded tipo de situação, o que não seria bom para o desempenho.

Existe uma maneira legal de lidar com essa situação que não inclui um regexp de validação (por exemplo, r"{%s+include") verifique se há inclusões durante o tempo de criação do modelo do usuário ("Certifique-se de que uma importação recursiva nunca fique no banco de dados, ou seu servidor irá asplode" não combina comigo).

Minha tentativa falhada

Eu comecei usando um carregador personalizado que contém apenas um usuário "s" inclui "::

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)

O problema em fazer isso é que eu basicamente me impedi de tirar proveito do Jinja2. Cache de Bytecode, o que claramente exigiria que todos os modelos estivessem disponíveis para um load(... chamada, que por sua vez chama get_source(....

Respostas:

3 para resposta № 1

Para analisar modelos e verificar inclui, eu uso este código:

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