diff --git a/django/core/cache/__init__.py b/django/core/cache/__init__.py index 05ef3897d0..a311b50af6 100644 --- a/django/core/cache/__init__.py +++ b/django/core/cache/__init__.py @@ -43,6 +43,13 @@ class CacheHandler(BaseConnectionHandler): ) from e return backend_cls(location, params) + def all(self, initialized_only=False): + return [ + self[alias] for alias in self + # If initialized_only is True, return only initialized caches. + if not initialized_only or hasattr(self._connections, alias) + ] + caches = CacheHandler() @@ -52,7 +59,7 @@ cache = ConnectionProxy(caches, DEFAULT_CACHE_ALIAS) def close_caches(**kwargs): # Some caches need to do a cleanup at the end of a request cycle. If not # implemented in a particular backend cache.close() is a no-op. - for cache in caches.all(): + for cache in caches.all(initialized_only=True): cache.close() diff --git a/docs/releases/3.2.4.txt b/docs/releases/3.2.4.txt index 068798e6ed..dac726e961 100644 --- a/docs/releases/3.2.4.txt +++ b/docs/releases/3.2.4.txt @@ -15,3 +15,6 @@ Bugfixes * Fixed a bug in Django 3.2 where a system check would crash on an abstract model (:ticket:`32733`). + +* Prevented unnecessary initialization of unused caches following a regression + in Django 3.2 (:ticket:`32747`). diff --git a/tests/cache/tests.py b/tests/cache/tests.py index c189e26e70..65a8f12fc7 100644 --- a/tests/cache/tests.py +++ b/tests/cache/tests.py @@ -1723,6 +1723,19 @@ class CacheClosingTests(SimpleTestCase): signals.request_finished.send(self.__class__) self.assertTrue(cache.closed) + def test_close_only_initialized(self): + with self.settings(CACHES={ + 'cache_1': { + 'BACKEND': 'cache.closeable_cache.CacheClass', + }, + 'cache_2': { + 'BACKEND': 'cache.closeable_cache.CacheClass', + }, + }): + self.assertEqual(caches.all(initialized_only=True), []) + signals.request_finished.send(self.__class__) + self.assertEqual(caches.all(initialized_only=True), []) + DEFAULT_MEMORY_CACHES_SETTINGS = { 'default': { @@ -2625,3 +2638,20 @@ class CacheHandlerTest(SimpleTestCase): ) with self.assertRaisesMessage(InvalidCacheBackendError, msg): test_caches['invalid_backend'] + + def test_all(self): + test_caches = CacheHandler({ + 'cache_1': { + 'BACKEND': 'django.core.cache.backends.dummy.DummyCache', + }, + 'cache_2': { + 'BACKEND': 'django.core.cache.backends.dummy.DummyCache', + }, + }) + self.assertEqual(test_caches.all(initialized_only=True), []) + cache_1 = test_caches['cache_1'] + self.assertEqual(test_caches.all(initialized_only=True), [cache_1]) + self.assertEqual(len(test_caches.all()), 2) + # .all() initializes all caches. + self.assertEqual(len(test_caches.all(initialized_only=True)), 2) + self.assertEqual(test_caches.all(), test_caches.all(initialized_only=True))