فهرست منبع

Fixed #27318 -- Made cache.set_many() return the list of failed keys.

Olivier Tabone 8 سال پیش
والد
کامیت
a027447f56
6فایلهای تغییر یافته به همراه36 افزوده شده و 6 حذف شده
  1. 1 0
      AUTHORS
  2. 4 0
      django/core/cache/backends/base.py
  3. 8 5
      django/core/cache/backends/memcached.py
  4. 2 1
      docs/releases/2.0.txt
  5. 7 0
      docs/topics/cache.txt
  6. 14 0
      tests/cache/tests.py

+ 1 - 0
AUTHORS

@@ -609,6 +609,7 @@ answer newbie questions, and generally made Django that much better:
     Oliver Beattie <oliver@obeattie.com>
     Oliver Rutherfurd <http://rutherfurd.net/>
     Olivier Sels <olivier.sels@gmail.com>
+    Olivier Tabone <olivier.tabone@ripplemotion.fr>
     Orestis Markou <orestis@orestis.gr>
     Orne Brocaar <http://brocaar.com/>
     Oscar Ramirez <tuxskar@gmail.com>

+ 4 - 0
django/core/cache/backends/base.py

@@ -206,9 +206,13 @@ class BaseCache:
 
         If timeout is given, use that timeout for the key; otherwise use the
         default cache timeout.
+
+        On backends that support it, return a list of keys that failed
+        insertion, or an empty list if all keys were inserted successfully.
         """
         for key, value in data.items():
             self.set(key, value, timeout=timeout, version=version)
+        return []
 
     def delete_many(self, keys, version=None):
         """

+ 8 - 5
django/core/cache/backends/memcached.py

@@ -134,11 +134,14 @@ class BaseMemcachedCache(BaseCache):
         return val
 
     def set_many(self, data, timeout=DEFAULT_TIMEOUT, version=None):
-        safe_data = {
-            self.make_key(key, version=version): value
-            for key, value in data.items()
-        }
-        self._cache.set_multi(safe_data, self.get_backend_timeout(timeout))
+        safe_data = {}
+        original_keys = {}
+        for key, value in data.items():
+            safe_key = self.make_key(key, version=version)
+            safe_data[safe_key] = value
+            original_keys[safe_key] = key
+        failed_keys = self._cache.set_multi(safe_data, self.get_backend_timeout(timeout))
+        return [original_keys[k] for k in failed_keys]
 
     def delete_many(self, keys, version=None):
         self._cache.delete_multi(self.make_key(key, version=version) for key in keys)

+ 2 - 1
docs/releases/2.0.txt

@@ -157,7 +157,8 @@ Minor features
 Cache
 ~~~~~
 
-* ...
+* On memcached, ``cache.set_many()`` returns a list of keys that failed to be
+  inserted.
 
 CSRF
 ~~~~

+ 7 - 0
docs/topics/cache.txt

@@ -881,6 +881,13 @@ of key-value pairs::
 
 Like ``cache.set()``, ``set_many()`` takes an optional ``timeout`` parameter.
 
+On supported backends (memcached), ``set_many()`` returns a list of keys that
+failed to be inserted.
+
+.. versionchanged:: 2.0
+
+    The return value containing list of failing keys was added.
+
 You can delete keys explicitly with ``delete()``. This is an easy way of
 clearing the cache for a particular object::
 

+ 14 - 0
tests/cache/tests.py

@@ -470,6 +470,11 @@ class BaseCacheTests:
         self.assertEqual(cache.get("key1"), "spam")
         self.assertEqual(cache.get("key2"), "eggs")
 
+    def test_set_many_returns_empty_list_on_success(self):
+        """set_many() returns an empty list when all keys are inserted."""
+        failing_keys = cache.set_many({'key1': 'spam', 'key2': 'eggs'})
+        self.assertEqual(failing_keys, [])
+
     def test_set_many_expiration(self):
         # set_many takes a second ``timeout`` parameter
         cache.set_many({"key1": "spam", "key2": "eggs"}, 1)
@@ -1239,6 +1244,13 @@ class BaseMemcachedTests(BaseCacheTests):
         finally:
             signals.request_finished.connect(close_old_connections)
 
+    def test_set_many_returns_failing_keys(self):
+        def fail_set_multi(mapping, *args, **kwargs):
+            return mapping.keys()
+        with mock.patch('%s.Client.set_multi' % self.client_library_name, side_effect=fail_set_multi):
+            failing_keys = cache.set_many({'key': 'value'})
+            self.assertEqual(failing_keys, ['key'])
+
 
 @unittest.skipUnless(MemcachedCache_params, "MemcachedCache backend not configured")
 @override_settings(CACHES=caches_setting_for_tests(
@@ -1247,6 +1259,7 @@ class BaseMemcachedTests(BaseCacheTests):
 ))
 class MemcachedCacheTests(BaseMemcachedTests, TestCase):
     base_params = MemcachedCache_params
+    client_library_name = 'memcache'
 
     def test_memcached_uses_highest_pickle_version(self):
         # Regression test for #19810
@@ -1270,6 +1283,7 @@ class MemcachedCacheTests(BaseMemcachedTests, TestCase):
 ))
 class PyLibMCCacheTests(BaseMemcachedTests, TestCase):
     base_params = PyLibMCCache_params
+    client_library_name = 'pylibmc'
     # libmemcached manages its own connections.
     should_disconnect_on_close = False