/ / Comment puis-je empêcher les appels circulaires {% include%} dans les modèles Jinja2 - python, django, template-engine, jinja2, circular-reference

Comment puis-je empêcher les appels circulaires {% include%} dans les modèles Jinja2 - python, django, template-engine, jinja2, circular-reference

Je possède une application Django SaaS avec des utilisateurs qui créent leurs propres modèles Jinja2 (dans un environnement extraordinairement en mode bac à sable, pour ceux qui viennent juste de crisser), qui sont enregistrés dans une base de données. j'ai un template_type champ, en notant si un modèle donné est un "include" ou un "modèle complet" (un modèle complet peut bien sûr inclure "includes"). Le problème est qu'un utilisateur peut mettre {% include "foo" %} dans un modèle appelé "bar", et {% include "bar" %} dans le "foo" modèle, provoquant une RuntimeError: maximum recursion depth exceeded type de situation, ce qui ne serait pas bon pour la performance.

Existe-t-il un bon moyen de gérer cette situation sans inclure une expression rationnelle de validation (par exemple, r"{%s+include") vérifie les inclus lors de la création du modèle utilisateur ("Assurez-vous qu’une importation récursive n’arrive jamais dans la base de données, sinon votre serveur utilisera le code" ne me plait pas vraiment ")

Ma tentative ratée

J'ai commencé par utiliser un chargeur personnalisé qui ne contient qu'un utilisateur "s" 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)

Le problème, c’est que j’ai essentiellement bloqué ma capacité à tirer parti de Jinja2 Cache Bytecode, ce qui exigerait clairement que tous les modèles soient disponibles pour une load(... call, qui à son tour appelle get_source(....

Réponses:

3 pour la réponse № 1

Pour analyser les modèles et vérifier les inclus, j'utilise ce code:

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