From c978dd93fda87c6d2e965d385164c35f1a3e64b8 Mon Sep 17 00:00:00 2001 From: Hasan Ramezani Date: Sun, 27 Dec 2020 21:21:59 +0100 Subject: [PATCH] Fixed #32290 -- Fixed TemplateNotFound in {% include %} tag for relative path in variable. --- django/template/loader_tags.py | 16 ++++++++++++---- .../relative_templates/dir1/dir2/inc3.html | 1 + tests/template_tests/test_extends_relative.py | 6 ++++++ 3 files changed, 19 insertions(+), 4 deletions(-) create mode 100644 tests/template_tests/relative_templates/dir1/dir2/inc3.html diff --git a/django/template/loader_tags.py b/django/template/loader_tags.py index b96214cad1..07b614c270 100644 --- a/django/template/loader_tags.py +++ b/django/template/loader_tags.py @@ -171,7 +171,10 @@ class IncludeNode(Node): # If not, try the cache and select_template(). template_name = template or () if isinstance(template_name, str): - template_name = (template_name,) + template_name = (construct_relative_path( + self.origin.template_name, + template_name, + ),) else: template_name = tuple(template_name) cache = context.render_context.dicts[0].setdefault(self, {}) @@ -226,7 +229,12 @@ def construct_relative_path(current_template_name, relative_name): Convert a relative path (starting with './' or '../') to the full template name based on the current_template_name. """ - if not relative_name.startswith(("'./", "'../", '"./', '"../')): + has_quotes = ( + (relative_name.startswith('"') and relative_name.endswith('"')) or + (relative_name.startswith("'") and relative_name.endswith("'")) + ) + new_name = relative_name.strip('\'"') + if not new_name.startswith(('./', '../')): # relative_name is a variable or a literal that doesn't contain a # relative path. return relative_name @@ -234,7 +242,7 @@ def construct_relative_path(current_template_name, relative_name): new_name = posixpath.normpath( posixpath.join( posixpath.dirname(current_template_name.lstrip('/')), - relative_name.strip('\'"') + new_name, ) ) if new_name.startswith('../'): @@ -248,7 +256,7 @@ def construct_relative_path(current_template_name, relative_name): "same template in which the tag appears." % (relative_name, current_template_name) ) - return '"%s"' % new_name + return f'"{new_name}"' if has_quotes else new_name @register.tag('extends') diff --git a/tests/template_tests/relative_templates/dir1/dir2/inc3.html b/tests/template_tests/relative_templates/dir1/dir2/inc3.html new file mode 100644 index 0000000000..7a8374df51 --- /dev/null +++ b/tests/template_tests/relative_templates/dir1/dir2/inc3.html @@ -0,0 +1 @@ +{% include tmpl %} diff --git a/tests/template_tests/test_extends_relative.py b/tests/template_tests/test_extends_relative.py index 9e8d7fc9b9..49a7624600 100644 --- a/tests/template_tests/test_extends_relative.py +++ b/tests/template_tests/test_extends_relative.py @@ -70,6 +70,12 @@ class IncludeRelativeBehaviorTests(SimpleTestCase): output = template.render(Context({})) self.assertEqual(output.strip(), 'dir2 include') + def test_normal_include_variable(self): + engine = Engine(dirs=[RELATIVE]) + template = engine.get_template('dir1/dir2/inc3.html') + output = template.render(Context({'tmpl': './include_content.html'})) + self.assertEqual(output.strip(), 'dir2 include') + def test_dir2_include(self): engine = Engine(dirs=[RELATIVE]) template = engine.get_template('dir1/dir2/inc1.html')