From ec704371e301c5450dd5fc012a30424a8f47b99b Mon Sep 17 00:00:00 2001
From: "Buddy Lindsey, Jr" <buddy@buddylindsey.com>
Date: Thu, 10 Sep 2015 15:54:19 -0500
Subject: [PATCH] Fixed #24765 -- Allowed template context updates to flatten a
 Context.

---
 django/template/context.py           | 10 +++++-
 tests/template_tests/test_context.py | 54 ++++++++++++++++++++++++++++
 2 files changed, 63 insertions(+), 1 deletion(-)

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