Created
August 30, 2013 05:01
-
-
Save loic/6386461 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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