summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGabriel Nick Pivovarov <113646197+gnpivo@users.noreply.github.com>2024-12-05 16:24:47 +0100
committerSarah Boyce <42296566+sarahboyce@users.noreply.github.com>2024-12-06 10:44:10 +0100
commit55855bc6d0d2a270eb34952c578ee352389367ad (patch)
tree638393b4f02d923470cbcf79e61161201aa1b57d
parentded485464214a3f69b64402b7d82221279f80008 (diff)
Fixed #35493 -- Allowed template self-inclusion with relative paths.
Co-authored-by: Brock <bsmick97@gmail.com>
-rw-r--r--django/template/loader_tags.py14
-rw-r--r--tests/template_tests/syntax_tests/test_include.py46
-rw-r--r--tests/template_tests/templates/recursive_relative_include.html7
3 files changed, 55 insertions, 12 deletions
diff --git a/django/template/loader_tags.py b/django/template/loader_tags.py
index 1874d8c528..36703b4782 100644
--- a/django/template/loader_tags.py
+++ b/django/template/loader_tags.py
@@ -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,
diff --git a/tests/template_tests/syntax_tests/test_include.py b/tests/template_tests/syntax_tests/test_include.py
index 3ee99b3798..be0deee926 100644
--- a/tests/template_tests/syntax_tests/test_include.py
+++ b/tests/template_tests/syntax_tests/test_include.py
@@ -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):
"""
diff --git a/tests/template_tests/templates/recursive_relative_include.html b/tests/template_tests/templates/recursive_relative_include.html
new file mode 100644
index 0000000000..ae49cc0a43
--- /dev/null
+++ b/tests/template_tests/templates/recursive_relative_include.html
@@ -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 %}