diff --git a/django/template/context.py b/django/template/context.py index b4aecb930e..b563e526f2 100644 --- a/django/template/context.py +++ b/django/template/context.py @@ -52,7 +52,13 @@ class BaseContext(object): yield d def push(self, *args, **kwargs): - return ContextDict(self, *args, **kwargs) + dicts = [] + for d in args: + if isinstance(d, BaseContext): + dicts += d.dicts[1:] + else: + dicts.append(d) + return ContextDict(self, *dicts, **kwargs) def pop(self): if len(self.dicts) == 1: @@ -175,6 +181,8 @@ class Context(BaseContext): "Pushes other_dict to the stack of dictionaries in the Context" if not hasattr(other_dict, '__getitem__'): raise TypeError('other_dict must be a mapping (dictionary-like) object.') + if isinstance(other_dict, BaseContext): + other_dict = other_dict.dicts[1:].pop() return ContextDict(self, other_dict) diff --git a/tests/template_tests/test_context.py b/tests/template_tests/test_context.py index d07edd3ef1..87b2016aa5 100644 --- a/tests/template_tests/test_context.py +++ b/tests/template_tests/test_context.py @@ -43,6 +43,46 @@ class ContextTests(SimpleTestCase): self.assertEqual(c['a'], 3) self.assertEqual(c['a'], 1) + def test_push_context_manager_with_context_object(self): + c = Context({'a': 1}) + with c.push(Context({'a': 3})): + self.assertEqual(c['a'], 3) + self.assertEqual(c['a'], 1) + + def test_update_context_manager_with_context_object(self): + c = Context({'a': 1}) + with c.update(Context({'a': 3})): + self.assertEqual(c['a'], 3) + self.assertEqual(c['a'], 1) + + def test_push_proper_layering(self): + c = Context({'a': 1}) + c.push(Context({'b': 2})) + c.push(Context({'c': 3, 'd': {'z': '26'}})) + self.assertEqual( + c.dicts, + [ + {'False': False, 'None': None, 'True': True}, + {'a': 1}, + {'b': 2}, + {'c': 3, 'd': {'z': '26'}}, + ] + ) + + def test_update_proper_layering(self): + c = Context({'a': 1}) + c.update(Context({'b': 2})) + c.update(Context({'c': 3, 'd': {'z': '26'}})) + self.assertEqual( + c.dicts, + [ + {'False': False, 'None': None, 'True': True}, + {'a': 1}, + {'b': 2}, + {'c': 3, 'd': {'z': '26'}}, + ] + ) + def test_setdefault(self): c = Context() @@ -96,6 +136,20 @@ class ContextTests(SimpleTestCase): 'a': 2, 'b': 4, 'c': 8 }) + def test_flatten_context_with_context(self): + """ + Context.push() with a Context argument should work. + """ + a = Context({'a': 2}) + a.push(Context({'z': '8'})) + self.assertEqual(a.flatten(), { + 'False': False, + 'None': None, + 'True': True, + 'a': 2, + 'z': '8', + }) + def test_context_comparable(self): """ #21765 -- equality comparison should work