/ / Wie kann ich zirkuläre {% include%} Aufrufe in Jinja2 Templates verhindern - Python, Django, Template-Engine, Jinja2, Zirkular-Referenz

Wie kann ich zirkuläre {% include%} Aufrufe in Jinja2-Templates verhindern - Python, Django, Template-Engine, Jinja2, Zirkular-Referenz

Ich habe eine Django SaaS-App mit Benutzern, die ihre eigenen Jinja2-Vorlagen erstellen (in einer außergewöhnlichen Sandbox-Umgebung, für diejenigen, die gerade krümmten), die in einer Datenbank gespeichert werden. Ich habe ein template_type Geben Sie an, ob eine Vorlage ein "include" oder eine "full template" ist (eine vollständige Vorlage kann natürlich "includes" enthalten). Das Problem ist, dass ein Benutzer setzen könnte {% include "foo" %} in eine Vorlage namens "bar", und {% include "bar" %} in die "foo" Vorlage, verursacht a RuntimeError: maximum recursion depth exceeded Art der Situation, die für die Leistung nicht gut wäre.

Gibt es einen schönen Weg, um diese Situation zu bewältigen, die nicht eine Validierung Regexp (z. B. r"{%s+include") Überprüfen Sie, ob während der Erstellung der Benutzervorlage Includes enthalten sind ("Stellen Sie sicher, dass ein rekursiver Import niemals in die Datenbank gelangt oder Ihr Server nicht asplodiert").

Mein fehlgeschlagener Versuch

Ich begann mit einem benutzerdefinierten Loader, der nur einen Benutzer enthält "s" enthält "::

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)

Das Problem dabei ist, dass ich mich im Grunde blockiert habe, um Jinja2s Vorteile nutzen zu können Bytecode-Cache, die eindeutig erfordern würde, dass alle Vorlagen für eine load(... Anruf, der wiederum anruft get_source(....

Antworten:

3 für die Antwort № 1

Um Vorlagen zu analysieren und Includes zu überprüfen, verwende ich diesen Code:

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