Fixed #26830 -- Prevented the 'with' templatetag from resetting the cycle variable to its initial state.

This commit is contained in:
Alexander Schrijver 2016-07-16 22:55:40 +02:00 committed by Tim Graham
parent 31e053edfa
commit 3ae3a1f9fa
4 changed files with 66 additions and 1 deletions

View File

@ -67,6 +67,18 @@ class BaseContext(object):
"Set a variable in the current context"
self.dicts[-1][key] = value
def set_upward(self, key, value):
"""
Set a variable in one of the higher contexts if it exists there,
otherwise in the current context.
"""
context = self.dicts[-1]
for d in reversed(self.dicts):
if key in d.keys():
context = d
break
context[key] = value
def __getitem__(self, key):
"Get a variable's value, starting at the current context and going upward"
for d in reversed(self.dicts):

View File

@ -82,7 +82,7 @@ class CycleNode(Node):
cycle_iter = context.render_context[self]
value = next(cycle_iter).resolve(context)
if self.variable_name:
context[self.variable_name] = value
context.set_upward(self.variable_name, value)
if self.silent:
return ''
return render_value_in_context(value, context)

View File

@ -145,3 +145,25 @@ class CycleTagTests(SimpleTestCase):
"""
output = self.engine.render_to_string('cycle29', {'values': [1, 2, 3, 4, 5, 6, 7, 8, 8, 8, 9, 9]})
self.assertEqual(output, 'bcabcabcccaa')
@setup({
'cycle30': "{% cycle 'a' 'b' 'c' as cycler silent %}"
"{% for x in values %}"
"{% with doesnothing=irrelevant %}"
"{% ifchanged x %}"
"{% cycle cycler %}{{ cycler }}"
"{% else %}"
"{{ cycler }}"
"{% endifchanged %}"
"{% endwith %}"
"{% endfor %}"})
def test_cycle30(self):
"""
A {% with %} tag shouldn't reset the {% cycle %} variable.
"""
output = self.engine.render_to_string(
'cycle30', {
'irrelevant': 1,
'values': [1, 2, 3, 4, 5, 6, 7, 8, 8, 8, 9, 9]
})
self.assertEqual(output, 'bcabcabcccaa')

View File

@ -204,6 +204,37 @@ class ContextTests(SimpleTestCase):
self.assertEqual(str(warns[2].message), msg2)
self.assertEqual(str(warns[3].message), msg2)
def test_set_upward(self):
c = Context({'a': 1})
c.set_upward('a', 2)
self.assertEqual(c.get('a'), 2)
def test_set_upward_empty_context(self):
empty_context = Context()
empty_context.set_upward('a', 1)
self.assertEqual(empty_context.get('a'), 1)
def test_set_upward_with_push(self):
"""
The highest context which has the given key is used.
"""
c = Context({'a': 1})
c.push({'a': 2})
c.set_upward('a', 3)
self.assertEqual(c.get('a'), 3)
c.pop()
self.assertEqual(c.get('a'), 1)
def test_set_upward_with_push_no_match(self):
"""
The highest context is used if the given key isn't found.
"""
c = Context({'b': 1})
c.push({'b': 2})
c.set_upward('a', 2)
self.assertEqual(len(c.dicts), 3)
self.assertEqual(c.dicts[-1]['a'], 2)
class RequestContextTests(SimpleTestCase):