1
0
mirror of https://github.com/django/django.git synced 2024-12-22 00:55:44 +00:00

Fixed #35493 -- Allowed template self-inclusion with relative paths.

Co-authored-by: Brock <bsmick97@gmail.com>
This commit is contained in:
Gabriel Nick Pivovarov 2024-12-05 16:24:47 +01:00 committed by Sarah Boyce
parent ded4854642
commit 55855bc6d0
3 changed files with 55 additions and 12 deletions

View File

@ -242,7 +242,11 @@ def do_block(parser, token):
return BlockNode(block_name, nodelist)
def construct_relative_path(current_template_name, relative_name):
def construct_relative_path(
current_template_name,
relative_name,
allow_recursion=False,
):
"""
Convert a relative path (starting with './' or '../') to the full template
name based on the current_template_name.
@ -264,7 +268,7 @@ def construct_relative_path(current_template_name, relative_name):
"The relative path '%s' points outside the file hierarchy that "
"template '%s' is in." % (relative_name, current_template_name)
)
if current_template_name.lstrip("/") == new_name:
if not allow_recursion and current_template_name.lstrip("/") == new_name:
raise TemplateSyntaxError(
"The relative path '%s' was translated to template name '%s', the "
"same template in which the tag appears."
@ -346,7 +350,11 @@ def do_include(parser, token):
options[option] = value
isolated_context = options.get("only", False)
namemap = options.get("with", {})
bits[1] = construct_relative_path(parser.origin.template_name, bits[1])
bits[1] = construct_relative_path(
parser.origin.template_name,
bits[1],
allow_recursion=True,
)
return IncludeNode(
parser.compile_filter(bits[1]),
extra_context=namemap,

View File

@ -330,15 +330,43 @@ class IncludeTests(SimpleTestCase):
],
}
]
engine = Engine(app_dirs=True)
t = engine.get_template("recursive_include.html")
self.assertEqual(
"Recursion! A1 Recursion! B1 B2 B3 Recursion! C1",
t.render(Context({"comments": comments}))
.replace(" ", "")
.replace("\n", " ")
.strip(),
)
with self.subTest(template="recursive_include.html"):
engine = Engine(app_dirs=True)
t = engine.get_template("recursive_include.html")
self.assertEqual(
"Recursion! A1 Recursion! B1 B2 B3 Recursion! C1",
t.render(Context({"comments": comments}))
.replace(" ", "")
.replace("\n", " ")
.strip(),
)
with self.subTest(template="recursive_relative_include.html"):
engine = Engine(app_dirs=True)
t = engine.get_template("recursive_relative_include.html")
self.assertEqual(
"Recursion! A1 Recursion! B1 B2 B3 Recursion! C1",
t.render(Context({"comments": comments}))
.replace(" ", "")
.replace("\n", " ")
.strip(),
)
with self.subTest(template="tmpl"):
engine = Engine()
template = """
Recursion!
{% for c in comments %}
{{ c.comment }}
{% if c.children %}{% include tmpl with comments=c.children %}{% endif %}
{% endfor %}
"""
outer_tmpl = engine.from_string("{% include tmpl %}")
output = outer_tmpl.render(
Context({"tmpl": engine.from_string(template), "comments": comments})
)
self.assertEqual(
"Recursion! A1 Recursion! B1 B2 B3 Recursion! C1",
output.replace(" ", "").replace("\n", " ").strip(),
)
def test_include_cache(self):
"""

View File

@ -0,0 +1,7 @@
Recursion!
{% for comment in comments %}
{{ comment.comment }}
{% if comment.children %}
{% include "./recursive_relative_include.html" with comments=comment.children %}
{% endif %}
{% endfor %}