diff --git a/AUTHORS b/AUTHORS index ea0b01926c..44b6a90700 100644 --- a/AUTHORS +++ b/AUTHORS @@ -229,6 +229,7 @@ answer newbie questions, and generally made Django that much better: Simon Greenhill Owen Griffiths Espen Grindhaug + Mike Grouchy Janos Guljas Thomas Güttler Horst Gutmann diff --git a/django/core/cache/__init__.py b/django/core/cache/__init__.py index 2a9e1a700b..457433925a 100644 --- a/django/core/cache/__init__.py +++ b/django/core/cache/__init__.py @@ -133,11 +133,9 @@ def get_cache(backend, **kwargs): "Could not find backend '%s': %s" % (backend, e)) cache = backend_cls(location, params) # Some caches -- python-memcached in particular -- need to do a cleanup at the - # end of a request cycle. If the cache provides a close() method, wire it up - # here. - if hasattr(cache, 'close'): - signals.request_finished.connect(cache.close) + # end of a request cycle. If not implemented in a particular backend + # cache.close is a no-op + signals.request_finished.connect(cache.close) return cache cache = get_cache(DEFAULT_CACHE_ALIAS) - diff --git a/django/core/cache/backends/base.py b/django/core/cache/backends/base.py index f7573b2e31..e28ebbe2cf 100644 --- a/django/core/cache/backends/base.py +++ b/django/core/cache/backends/base.py @@ -6,15 +6,18 @@ from django.core.exceptions import ImproperlyConfigured, DjangoRuntimeWarning from django.utils.encoding import smart_str from django.utils.importlib import import_module + class InvalidCacheBackendError(ImproperlyConfigured): pass + class CacheKeyWarning(DjangoRuntimeWarning): pass # Memcached does not accept keys longer than this. MEMCACHE_MAX_KEY_LENGTH = 250 + def default_key_func(key, key_prefix, version): """ Default function to generate keys. @@ -25,6 +28,7 @@ def default_key_func(key, key_prefix, version): """ return ':'.join([key_prefix, str(version), smart_str(key)]) + def get_key_func(key_func): """ Function to decide which key function to use. @@ -40,6 +44,7 @@ def get_key_func(key_func): return getattr(key_func_module, key_func_name) return default_key_func + class BaseCache(object): def __init__(self, params): timeout = params.get('timeout', params.get('TIMEOUT', 300)) @@ -221,3 +226,7 @@ class BaseCache(object): the new version. """ return self.incr_version(key, -delta, version) + + def close(self, **kwargs): + """Close the cache connection""" + pass diff --git a/docs/topics/cache.txt b/docs/topics/cache.txt index 03afa86647..85f4c64aa8 100644 --- a/docs/topics/cache.txt +++ b/docs/topics/cache.txt @@ -779,6 +779,16 @@ nonexistent cache key.:: However, if the backend doesn't natively provide an increment/decrement operation, it will be implemented using a two-step retrieve/update. + +You can close the connection to your cache with ``close()`` if implemented by +the cache backend. + + >>> cache.close() + +.. note:: + + For caches that don't implement ``close`` methods it is a no-op. + .. _cache_key_prefixing: Cache key prefixing diff --git a/tests/regressiontests/cache/tests.py b/tests/regressiontests/cache/tests.py index 264ef74abd..b85c8d4cf3 100644 --- a/tests/regressiontests/cache/tests.py +++ b/tests/regressiontests/cache/tests.py @@ -266,6 +266,10 @@ class BaseCacheTests(object): self.assertEqual(self.cache.get('answer'), 32) self.assertRaises(ValueError, self.cache.decr, 'does_not_exist') + def test_close(self): + self.assertTrue(hasattr(self.cache, 'close')) + self.cache.close() + def test_data_types(self): # Many different data types can be cached stuff = {