summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorkapil garg <kapilgarg1996@users.noreply.github.com>2017-04-04 07:59:39 +0530
committerTim Graham <timograham@gmail.com>2017-04-03 22:32:41 -0400
commit76b51656e6162902daa6bf6ec3fe04b1ca960a72 (patch)
tree50da547002e3a1815e674a4c82bb9199109a55e6
parent8165863a67d2dcfd154a172c5fc33088fd6e9523 (diff)
[1.11.x] Fixed #27974 -- Kept resolved templates constant during one rendering cycle.
Thanks Florian Apolloner for the initial patch. Backport of 002fe076225c2aa6e389481b038f55acb6f807d0 from master
-rw-r--r--django/template/loader_tags.py2
-rw-r--r--tests/template_tests/syntax_tests/test_if_changed.py11
-rw-r--r--tests/template_tests/syntax_tests/test_include.py20
-rw-r--r--tests/template_tests/templatetags/custom.py15
4 files changed, 47 insertions, 1 deletions
diff --git a/django/template/loader_tags.py b/django/template/loader_tags.py
index 020f2e412a..c3804adc1d 100644
--- a/django/template/loader_tags.py
+++ b/django/template/loader_tags.py
@@ -198,7 +198,7 @@ class IncludeNode(Node):
if not callable(getattr(template, 'render', None)):
# If not, we'll try our cache, and get_template()
template_name = template
- cache = context.render_context.setdefault(self.context_key, {})
+ cache = context.render_context.dicts[0].setdefault(self, {})
template = cache.get(template_name)
if template is None:
template = context.template.engine.get_template(template_name)
diff --git a/tests/template_tests/syntax_tests/test_if_changed.py b/tests/template_tests/syntax_tests/test_if_changed.py
index bf8a95d8a4..ced81e9865 100644
--- a/tests/template_tests/syntax_tests/test_if_changed.py
+++ b/tests/template_tests/syntax_tests/test_if_changed.py
@@ -212,3 +212,14 @@ class IfChangedTests(SimpleTestCase):
])
output = engine.render_to_string('template', dict(vars=[1, 1, 2, 2, 3, 3]))
self.assertEqual(output, "123")
+
+ def test_include_state(self):
+ """Tests the node state for different IncludeNodes (#27974)."""
+ engine = Engine(loaders=[
+ ('django.template.loaders.locmem.Loader', {
+ 'template': '{% for x in vars %}{% include "include" %}{% include "include" %}{% endfor %}',
+ 'include': '{% ifchanged %}{{ x }}{% endifchanged %}',
+ }),
+ ])
+ output = engine.render_to_string('template', dict(vars=[1, 1, 2, 2, 3, 3]))
+ self.assertEqual(output, '112233')
diff --git a/tests/template_tests/syntax_tests/test_include.py b/tests/template_tests/syntax_tests/test_include.py
index 185bcb3988..3368522065 100644
--- a/tests/template_tests/syntax_tests/test_include.py
+++ b/tests/template_tests/syntax_tests/test_include.py
@@ -311,3 +311,23 @@ class IncludeTests(SimpleTestCase):
"Recursion! A1 Recursion! B1 B2 B3 Recursion! C1",
t.render(Context({'comments': comments})).replace(' ', '').replace('\n', ' ').strip(),
)
+
+ def test_include_cache(self):
+ """
+ {% include %} keeps resolved templates constant (#27974). The
+ CounterNode object in the {% counter %} template tag is created once
+ if caching works properly. Each iteration increases the counter instead
+ of restarting it.
+
+ This works as a regression test only if the cached loader
+ isn't used, so the @setup decorator isn't used.
+ """
+ engine = Engine(loaders=[
+ ('django.template.loaders.locmem.Loader', {
+ 'template': '{% for x in vars %}{% include "include" %}{% endfor %}',
+ 'include': '{% include "next" %}',
+ 'next': '{% load custom %}{% counter %}'
+ }),
+ ], libraries={'custom': 'template_tests.templatetags.custom'})
+ output = engine.render_to_string('template', dict(vars=range(9)))
+ self.assertEqual(output, '012345678')
diff --git a/tests/template_tests/templatetags/custom.py b/tests/template_tests/templatetags/custom.py
index fffef022ac..a6f5936e0e 100644
--- a/tests/template_tests/templatetags/custom.py
+++ b/tests/template_tests/templatetags/custom.py
@@ -184,3 +184,18 @@ with warnings.catch_warnings():
"""Expected assignment_tag_without_context_parameter __doc__"""
return "Expected result"
assignment_tag_without_context_parameter.anything = "Expected assignment_tag_without_context_parameter __dict__"
+
+
+@register.tag('counter')
+def counter(parser, token):
+ return CounterNode()
+
+
+class CounterNode(template.Node):
+ def __init__(self):
+ self.count = 0
+
+ def render(self, context):
+ count = self.count
+ self.count = count + 1
+ return count