Skip to content

Instantly share code, notes, and snippets.

@loic
Created August 30, 2013 05:01
Show Gist options
  • Save loic/6386461 to your computer and use it in GitHub Desktop.
Save loic/6386461 to your computer and use it in GitHub Desktop.
diff --git a/django/template/loader_tags.py b/django/template/loader_tags.py
index d7908ac..4ba95ec 100644
--- a/django/template/loader_tags.py
+++ b/django/template/loader_tags.py
@@ -121,55 +121,34 @@ class ExtendsNode(Node):
# the same.
return compiled_parent._render(context)
-class BaseIncludeNode(Node):
- def __init__(self, *args, **kwargs):
+class IncludeNode(Node):
+ def __init__(self, template, *args, **kwargs):
+ self.template = template
self.extra_context = kwargs.pop('extra_context', {})
self.isolated_context = kwargs.pop('isolated_context', False)
- super(BaseIncludeNode, self).__init__(*args, **kwargs)
-
- def render_template(self, template, context):
- values = dict([(name, var.resolve(context)) for name, var
- in six.iteritems(self.extra_context)])
- if self.isolated_context:
- return template.render(context.new(values))
- with context.push(**values):
- return template.render(context)
-
-
-class ConstantIncludeNode(BaseIncludeNode):
- def __init__(self, template_path, *args, **kwargs):
- super(ConstantIncludeNode, self).__init__(*args, **kwargs)
- try:
- t = get_template(template_path)
- self.template = t
- except:
- if settings.TEMPLATE_DEBUG:
- raise
- self.template = None
-
- def render(self, context):
- if not self.template:
- return ''
- return self.render_template(self.template, context)
-
-class IncludeNode(BaseIncludeNode):
- def __init__(self, template_name, *args, **kwargs):
super(IncludeNode, self).__init__(*args, **kwargs)
- self.template_name = template_name
def render(self, context):
try:
- template = self.template_name.resolve(context)
+ template = self.template.resolve(context)
# Does this quack like a Template?
if not callable(getattr(template, 'render', None)):
# If not, we'll try get_template
template = get_template(template)
- return self.render_template(template, context)
+ values = dict([
+ (name, var.resolve(context))
+ for name, var in six.iteritems(self.extra_context)
+ ])
+ if self.isolated_context:
+ return template.render(context.new(values))
+ with context.push(**values):
+ return template.render(context)
except:
if settings.TEMPLATE_DEBUG:
raise
return ''
+
@register.tag('block')
def do_block(parser, token):
"""
@@ -258,9 +237,5 @@ def do_include(parser, token):
options[option] = value
isolated_context = options.get('only', False)
namemap = options.get('with', {})
- path = bits[1]
- if path[0] in ('"', "'") and path[-1] == path[0]:
- return ConstantIncludeNode(path[1:-1], extra_context=namemap,
- isolated_context=isolated_context)
return IncludeNode(parser.compile_filter(bits[1]), extra_context=namemap,
isolated_context=isolated_context)
diff --git a/tests/template_tests/templates/recursive_include.html b/tests/template_tests/templates/recursive_include.html
new file mode 100644
index 0000000..dc848f3
--- /dev/null
+++ b/tests/template_tests/templates/recursive_include.html
@@ -0,0 +1,7 @@
+Recursion!
+{% for comment in comments %}
+ {{ comment.comment }}
+ {% if comment.children %}
+ {% include "recursive_include.html" with comments=comment.children %}
+ {% endif %}
+{% endfor %}
diff --git a/tests/template_tests/tests.py b/tests/template_tests/tests.py
index e9c0a0f..37148db 100644
--- a/tests/template_tests/tests.py
+++ b/tests/template_tests/tests.py
@@ -349,6 +349,19 @@ class TemplateLoaderTests(TestCase):
output = outer_tmpl.render(ctx)
self.assertEqual(output, 'This worked!')
+ @override_settings(TEMPLATE_DEBUG=True)
+ def test_include_immediate_missing(self):
+ """
+ Regression test for #16417 -- {% include %} tag raises TemplateDoesNotExist at compile time if TEMPLATE_DEBUG is True
+
+ Test that an {% include %} tag with a literal string referencing a
+ template that does not exist does not raise an exception at parse
+ time.
+ """
+ ctx = Context()
+ tmpl = Template('{% include "this_does_not_exist.html" %}')
+ self.assertIsInstance(tmpl, Template)
+
class TemplateRegressionTests(TestCase):
@@ -1852,3 +1865,26 @@ class RequestContextTests(unittest.TestCase):
# The stack should now contain 3 items:
# [builtins, supplied context, context processor]
self.assertEqual(len(ctx.dicts), 3)
+
+
+class RecursiveIncludesTests(unittest.TestCase):
+ @override_settings(TEMPLATE_DEBUG=True)
+ def test(self):
+ comments = [
+ {
+ 'comment': 'A1',
+ 'children': [
+ {'comment': 'B1', 'children': []},
+ {'comment': 'B2', 'children': []},
+ {'comment': 'B3', 'children': [
+ {'comment': 'C1', 'children': []}
+ ]},
+ ]
+ }
+ ]
+
+ t = loader.get_template('recursive_include.html')
+ self.assertEqual(
+ "Recursion! A1 Recursion! B1 B2 B3 Recursion! C1",
+ t.render(Context({'comments': comments})).replace(' ', '').replace('\n', ' ').strip(),
+ )
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment