Fixed #27974 -- Kept resolved templates constant during one rendering cycle.

Thanks Florian Apolloner for the initial patch.
This commit is contained in:
kapil garg 2017-04-04 07:59:39 +05:30 committed by Tim Graham
parent ef8a339dfb
commit 002fe07622
4 changed files with 47 additions and 1 deletions

View File

@ -176,7 +176,7 @@ class IncludeNode(Node):
if not callable(getattr(template, 'render', None)): if not callable(getattr(template, 'render', None)):
# If not, we'll try our cache, and get_template() # If not, we'll try our cache, and get_template()
template_name = 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) template = cache.get(template_name)
if template is None: if template is None:
template = context.template.engine.get_template(template_name) template = context.template.engine.get_template(template_name)

View File

@ -212,3 +212,14 @@ class IfChangedTests(SimpleTestCase):
]) ])
output = engine.render_to_string('template', dict(vars=[1, 1, 2, 2, 3, 3])) output = engine.render_to_string('template', dict(vars=[1, 1, 2, 2, 3, 3]))
self.assertEqual(output, "123") 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')

View File

@ -308,3 +308,23 @@ class IncludeTests(SimpleTestCase):
"Recursion! A1 Recursion! B1 B2 B3 Recursion! C1", "Recursion! A1 Recursion! B1 B2 B3 Recursion! C1",
t.render(Context({'comments': comments})).replace(' ', '').replace('\n', ' ').strip(), 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')

View File

@ -166,3 +166,18 @@ def minustwo_overridden_name(value):
register.simple_tag(lambda x: x - 1, name='minusone') register.simple_tag(lambda x: x - 1, name='minusone')
@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