소스 검색

Made the new template.Context.flatten() method a public API.

That method was introduced in 9db4271bd11ac23a5a5652bbcdf8fb6d4b997651.

Refs #21765.
Marek Wywiał 11 년 전
부모
커밋
8274fa60f8
4개의 변경된 파일66개의 추가작업 그리고 7개의 파일을 삭제
  1. 10 7
      django/template/context.py
  2. 37 0
      docs/ref/templates/api.txt
  3. 8 0
      docs/releases/1.7.txt
  4. 11 0
      tests/template_tests/test_context.py

+ 10 - 7
django/template/context.py

@@ -97,6 +97,15 @@ class BaseContext(object):
         new_context._reset_dicts(values)
         return new_context
 
+    def flatten(self):
+        """
+        Returns self.dicts as one dictionary
+        """
+        flat = {}
+        for d in self.dicts:
+            flat.update(d)
+        return flat
+
     def __eq__(self, other):
         """
         Compares two contexts by comparing theirs 'dicts' attributes.
@@ -104,13 +113,7 @@ class BaseContext(object):
         if isinstance(other, BaseContext):
             # because dictionaries can be put in different order
             # we have to flatten them like in templates
-            def flatten(dicts):
-                flat = {}
-                for d in dicts:
-                    flat.update(d)
-                return flat
-
-            return flatten(self.dicts) == flatten(other.dicts)
+            return self.flatten() == other.flatten()
 
         # if it's not comparable return false
         return False

+ 37 - 0
docs/ref/templates/api.txt

@@ -368,6 +368,43 @@ the stack instead of an empty one.
 Using a ``Context`` as a stack comes in handy in some custom template tags, as
 you'll see below.
 
+.. method:: Context.flatten()
+
+.. versionadded:: 1.7
+
+Using ``flatten()`` method you can get whole ``Context`` stack as one dictionary
+including builtin variables.
+
+    >>> c = Context()
+    >>> c['foo'] = 'first level'
+    >>> c.update({'bar': 'second level'})
+    {'bar': 'second level'}
+    >>> c.flatten()
+    {'True': True, 'None': None, 'foo': 'first level', 'False': False, 'bar': 'second level'}
+
+A ``flatten()`` method is also internally used to make ``Context`` objects comparable.
+
+    >>> c1 = Context()
+    >>> c1['foo'] = 'first level'
+    >>> c1['bar'] = 'second level'
+    >>> c2 = Context()
+    >>> c2.update({'bar': 'second level', 'foo': 'first level'})
+    {'foo': 'first level', 'bar': 'second level'}
+    >>> c1 == c2
+    True
+
+Result from ``flatten()`` can be useful in unit tests to compare ``Context``
+against ``dict``::
+
+    class ContextTest(unittest.TestCase):
+        def test_against_dictionary(self):
+            c1 = Context()
+            c1['update'] = 'value'
+            self.assertEqual(c1.flatten(), {
+                'True': True, 'None': None, 'False': False,
+                'update': 'value'})
+
+
 .. _subclassing-context-requestcontext:
 
 Subclassing Context: RequestContext

+ 8 - 0
docs/releases/1.7.txt

@@ -636,6 +636,14 @@ Templates
   parameters that are passed to the ``dict`` constructor used to build the new
   context level.
 
+* The new :meth:`Context.flatten() <django.template.Context.flatten>` method
+  returns a ``Context``'s stack as one flat dictionary.
+
+* ``Context`` objects can now be compared for equality (internally, this
+  uses :meth:`Context.flatten() <django.template.Context.flatten>` so the
+  internal structure of each ``Context``'s stack doesn't matter as long as their
+  flattened version is identical).
+
 * The :ttag:`widthratio` template tag now accepts an "as" parameter to capture
   the result in a variable.
 

+ 11 - 0
tests/template_tests/test_context.py

@@ -50,6 +50,17 @@ class ContextTests(TestCase):
             test_context['fruit']
         self.assertIsNone(test_context.get('fruit'))
 
+    def test_flatten_context(self):
+        a = Context()
+        a.update({'a': 2})
+        a.update({'b': 4})
+        a.update({'c': 8})
+
+        self.assertEqual(a.flatten(), {
+            'False': False, 'None': None, 'True': True,
+            'a': 2, 'b': 4, 'c': 8
+        })
+
     def test_context_comparable(self):
         test_data = {'x': 'y', 'v': 'z', 'd': {'o': object, 'a': 'b'}}