浏览代码

Fixed #22691 -- Added aliasing to cached_property.

Curtis 10 年之前
父节点
当前提交
71461b14ab
共有 3 个文件被更改,包括 34 次插入3 次删除
  1. 6 2
      django/utils/functional.py
  2. 19 1
      docs/ref/utils.txt
  3. 9 0
      tests/utils_tests/test_functional.py

+ 6 - 2
django/utils/functional.py

@@ -45,14 +45,18 @@ class cached_property(object):
     """
     Decorator that converts a method with a single self argument into a
     property cached on the instance.
+
+    Optional ``name`` argument allows you to make cached properties of other
+    methods. (e.g.  url = cached_property(get_absolute_url, name='url') )
     """
-    def __init__(self, func):
+    def __init__(self, func, name=None):
         self.func = func
+        self.name = name or func.__name__
 
     def __get__(self, instance, type=None):
         if instance is None:
             return self
-        res = instance.__dict__[self.func.__name__] = self.func(instance)
+        res = instance.__dict__[self.name] = self.func(instance)
         return res
 
 

+ 19 - 1
docs/ref/utils.txt

@@ -423,7 +423,7 @@ Atom1Feed
 .. module:: django.utils.functional
     :synopsis: Functional programming tools.
 
-.. class:: cached_property(object)
+.. class:: cached_property(object, name)
 
     The ``@cached_property`` decorator caches the result of a method with a
     single ``self`` argument as a property. The cached result will persist
@@ -483,6 +483,24 @@ Atom1Feed
     database by some other process in the brief interval between subsequent
     invocations of a method on the same instance.
 
+    .. versionadded:: 1.8
+
+    You can use the ``name`` argument to make cached properties of other
+    methods. For example, if you had an expensive ``get_friends()`` method and
+    wanted to allow calling it without retrieving the cached value, you could
+    write::
+
+        friends = cached_property(get_friends, name='friends')
+
+    While ``person.get_friends()`` will recompute the friends on each call, the
+    value of the cached property will persist until you delete it as described
+    above::
+
+        x = person.friends         # calls first time
+        y = person.get_friends()   # calls again
+        z = person.friends         # does not call
+        x is z                     # is True
+
 .. function:: allow_lazy(func, *resultclasses)
 
     Django offers many utility functions (particularly in ``django.utils``)

+ 9 - 0
tests/utils_tests/test_functional.py

@@ -52,6 +52,11 @@ class FunctionalTestCase(unittest.TestCase):
             def value(self):
                 return 1, object()
 
+            def other_value(self):
+                return 1
+
+            other = cached_property(other_value, name='other')
+
         a = A()
 
         # check that it is cached
@@ -67,6 +72,10 @@ class FunctionalTestCase(unittest.TestCase):
         # check that it behaves like a property when there's no instance
         self.assertIsInstance(A.value, cached_property)
 
+        # check that overriding name works
+        self.assertEqual(a.other, 1)
+        self.assertTrue(callable(a.other_value))
+
     def test_lazy_equality(self):
         """
         Tests that == and != work correctly for Promises.