Loading django/core/cache/backends/base.py +5 −5 Original line number Diff line number Diff line Loading @@ -154,8 +154,7 @@ class BaseCache(object): also be any callable. If timeout is given, that timeout will be used for the key; otherwise the default cache timeout will be used. Returns the value of the key stored or retrieved on success, False on error. Return the value of the key stored or retrieved. """ if default is None: raise ValueError('You need to specify a value.') Loading @@ -163,9 +162,10 @@ class BaseCache(object): if val is None: if callable(default): default = default() val = self.add(key, default, timeout=timeout, version=version) if val: return self.get(key, default, version) self.add(key, default, timeout=timeout, version=version) # Fetch the value again to avoid a race condition if another caller # added a value between the first get() and the add() above. return self.get(key, default, version=version) return val def has_key(self, key, version=None): Loading docs/releases/1.9.5.txt +4 −0 Original line number Diff line number Diff line Loading @@ -12,3 +12,7 @@ Bugfixes * Made ``MultiPartParser`` ignore filenames that normalize to an empty string to fix crash in ``MemoryFileUploadHandler`` on specially crafted user input (:ticket:`26325`). * Fixed a race condition in ``BaseCache.get_or_set()`` (:ticket:`26332`). It now returns the ``default`` value instead of ``False`` if there's an error when trying to add the value to the cache. tests/cache/tests.py +8 −1 Original line number Diff line number Diff line Loading @@ -30,7 +30,7 @@ from django.template import engines from django.template.context_processors import csrf from django.template.response import TemplateResponse from django.test import ( RequestFactory, SimpleTestCase, TestCase, TransactionTestCase, RequestFactory, SimpleTestCase, TestCase, TransactionTestCase, mock, override_settings, ) from django.test.signals import setting_changed Loading Loading @@ -931,6 +931,13 @@ class BaseCacheTests(object): self.assertEqual(cache.get_or_set('brian', 1979, version=2), 1979) self.assertIsNone(cache.get('brian', version=3)) def test_get_or_set_racing(self): with mock.patch('%s.%s' % (settings.CACHES['default']['BACKEND'], 'add')) as cache_add: # Simulate cache.add() failing to add a value. In that case, the # default value should be returned. cache_add.return_value = False self.assertEqual(cache.get_or_set('key', 'default'), 'default') @override_settings(CACHES=caches_setting_for_tests( BACKEND='django.core.cache.backends.db.DatabaseCache', Loading Loading
django/core/cache/backends/base.py +5 −5 Original line number Diff line number Diff line Loading @@ -154,8 +154,7 @@ class BaseCache(object): also be any callable. If timeout is given, that timeout will be used for the key; otherwise the default cache timeout will be used. Returns the value of the key stored or retrieved on success, False on error. Return the value of the key stored or retrieved. """ if default is None: raise ValueError('You need to specify a value.') Loading @@ -163,9 +162,10 @@ class BaseCache(object): if val is None: if callable(default): default = default() val = self.add(key, default, timeout=timeout, version=version) if val: return self.get(key, default, version) self.add(key, default, timeout=timeout, version=version) # Fetch the value again to avoid a race condition if another caller # added a value between the first get() and the add() above. return self.get(key, default, version=version) return val def has_key(self, key, version=None): Loading
docs/releases/1.9.5.txt +4 −0 Original line number Diff line number Diff line Loading @@ -12,3 +12,7 @@ Bugfixes * Made ``MultiPartParser`` ignore filenames that normalize to an empty string to fix crash in ``MemoryFileUploadHandler`` on specially crafted user input (:ticket:`26325`). * Fixed a race condition in ``BaseCache.get_or_set()`` (:ticket:`26332`). It now returns the ``default`` value instead of ``False`` if there's an error when trying to add the value to the cache.
tests/cache/tests.py +8 −1 Original line number Diff line number Diff line Loading @@ -30,7 +30,7 @@ from django.template import engines from django.template.context_processors import csrf from django.template.response import TemplateResponse from django.test import ( RequestFactory, SimpleTestCase, TestCase, TransactionTestCase, RequestFactory, SimpleTestCase, TestCase, TransactionTestCase, mock, override_settings, ) from django.test.signals import setting_changed Loading Loading @@ -931,6 +931,13 @@ class BaseCacheTests(object): self.assertEqual(cache.get_or_set('brian', 1979, version=2), 1979) self.assertIsNone(cache.get('brian', version=3)) def test_get_or_set_racing(self): with mock.patch('%s.%s' % (settings.CACHES['default']['BACKEND'], 'add')) as cache_add: # Simulate cache.add() failing to add a value. In that case, the # default value should be returned. cache_add.return_value = False self.assertEqual(cache.get_or_set('key', 'default'), 'default') @override_settings(CACHES=caches_setting_for_tests( BACKEND='django.core.cache.backends.db.DatabaseCache', Loading