diff --git a/AUTHORS b/AUTHORS index ffcc34d5dd..ceb5f1a7c7 100644 --- a/AUTHORS +++ b/AUTHORS @@ -129,6 +129,7 @@ answer newbie questions, and generally made Django that much better: Jure Cuhalev John D'Agostino dackze+django@gmail.com + Jim Dalton Mihai Damian David Danier Dirk Datzert diff --git a/django/core/cache/__init__.py b/django/core/cache/__init__.py index a30aa390ac..ced9875b07 100644 --- a/django/core/cache/__init__.py +++ b/django/core/cache/__init__.py @@ -110,6 +110,7 @@ def parse_backend_conf(backend, **kwargs): conf = settings.CACHES.get(backend, None) if conf is not None: args = conf.copy() + args.update(kwargs) backend = args.pop('BACKEND') location = args.pop('LOCATION', '') return backend, location, args diff --git a/django/middleware/cache.py b/django/middleware/cache.py index 31a8147eec..907edbb16f 100644 --- a/django/middleware/cache.py +++ b/django/middleware/cache.py @@ -65,7 +65,8 @@ class UpdateCacheMiddleware(object): self.cache_timeout = settings.CACHE_MIDDLEWARE_SECONDS self.key_prefix = settings.CACHE_MIDDLEWARE_KEY_PREFIX self.cache_anonymous_only = getattr(settings, 'CACHE_MIDDLEWARE_ANONYMOUS_ONLY', False) - self.cache = get_cache(settings.CACHE_MIDDLEWARE_ALIAS) + self.cache_alias = settings.CACHE_MIDDLEWARE_ALIAS + self.cache = get_cache(self.cache_alias) def process_response(self, request, response): """Sets the cache, if needed.""" @@ -101,7 +102,8 @@ class FetchFromCacheMiddleware(object): self.cache_timeout = settings.CACHE_MIDDLEWARE_SECONDS self.key_prefix = settings.CACHE_MIDDLEWARE_KEY_PREFIX self.cache_anonymous_only = getattr(settings, 'CACHE_MIDDLEWARE_ANONYMOUS_ONLY', False) - self.cache = get_cache(settings.CACHE_MIDDLEWARE_ALIAS) + self.cache_alias = settings.CACHE_MIDDLEWARE_ALIAS + self.cache = get_cache(self.cache_alias) def process_request(self, request): """ @@ -152,8 +154,9 @@ class CacheMiddleware(UpdateCacheMiddleware, FetchFromCacheMiddleware): # we need to use middleware defaults. cache_kwargs = {} + try: - self.key_prefix = kwargs.get('key_prefix') + self.key_prefix = kwargs['key_prefix'] if self.key_prefix is not None: cache_kwargs['KEY_PREFIX'] = self.key_prefix else: @@ -161,14 +164,15 @@ class CacheMiddleware(UpdateCacheMiddleware, FetchFromCacheMiddleware): except KeyError: self.key_prefix = settings.CACHE_MIDDLEWARE_KEY_PREFIX cache_kwargs['KEY_PREFIX'] = self.key_prefix + try: - cache_alias = kwargs.get('cache_alias') - if cache_alias is None: - cache_alias = DEFAULT_CACHE_ALIAS + self.cache_alias = kwargs['cache_alias'] + if self.cache_alias is None: + self.cache_alias = DEFAULT_CACHE_ALIAS if cache_timeout is not None: cache_kwargs['TIMEOUT'] = cache_timeout except KeyError: - cache_alias = settings.CACHE_MIDDLEWARE_ALIAS + self.cache_alias = settings.CACHE_MIDDLEWARE_ALIAS if cache_timeout is None: cache_kwargs['TIMEOUT'] = settings.CACHE_MIDDLEWARE_SECONDS else: @@ -179,5 +183,5 @@ class CacheMiddleware(UpdateCacheMiddleware, FetchFromCacheMiddleware): else: self.cache_anonymous_only = cache_anonymous_only - self.cache = get_cache(cache_alias, **cache_kwargs) + self.cache = get_cache(self.cache_alias, **cache_kwargs) self.cache_timeout = self.cache.default_timeout diff --git a/tests/regressiontests/cache/tests.py b/tests/regressiontests/cache/tests.py index f2cfcb37da..1a1e2438bd 100644 --- a/tests/regressiontests/cache/tests.py +++ b/tests/regressiontests/cache/tests.py @@ -1133,10 +1133,14 @@ class CacheMiddlewareTest(unittest.TestCase): def setUp(self): self.orig_cache_middleware_alias = settings.CACHE_MIDDLEWARE_ALIAS self.orig_cache_middleware_key_prefix = settings.CACHE_MIDDLEWARE_KEY_PREFIX + self.orig_cache_middleware_seconds = settings.CACHE_MIDDLEWARE_SECONDS + self.orig_cache_middleware_anonymous_only = getattr(settings, 'CACHE_MIDDLEWARE_ANONYMOUS_ONLY', False) self.orig_caches = settings.CACHES settings.CACHE_MIDDLEWARE_ALIAS = 'other' settings.CACHE_MIDDLEWARE_KEY_PREFIX = 'middlewareprefix' + settings.CACHE_MIDDLEWARE_SECONDS = 30 + settings.CACHE_MIDDLEWARE_ANONYMOUS_ONLY = False settings.CACHES = { 'default': { 'BACKEND': 'django.core.cache.backends.locmem.LocMemCache' @@ -1151,8 +1155,42 @@ class CacheMiddlewareTest(unittest.TestCase): def tearDown(self): settings.CACHE_MIDDLEWARE_ALIAS = self.orig_cache_middleware_alias settings.CACHE_MIDDLEWARE_KEY_PREFIX = self.orig_cache_middleware_key_prefix + settings.CACHE_MIDDLEWARE_SECONDS = self.orig_cache_middleware_seconds + settings.CACHE_MIDDLEWARE_ANONYMOUS_ONLY = self.orig_cache_middleware_anonymous_only settings.CACHES = self.orig_caches + def test_constructor(self): + """ + Ensure the constructor is correctly distinguishing between usage of CacheMiddleware as + Middleware vs. usage of CacheMiddleware as view decorator and setting attributes + appropriately. + """ + # If no arguments are passed in construction, it's being used as middleware. + middleware = CacheMiddleware() + + # Now test object attributes against values defined in setUp above + self.assertEquals(middleware.cache_timeout, 30) + self.assertEquals(middleware.key_prefix, 'middlewareprefix') + self.assertEquals(middleware.cache_alias, 'other') + self.assertEquals(middleware.cache_anonymous_only, False) + + # If arguments are being passed in construction, it's being used as a decorator. + # First, test with "defaults": + as_view_decorator = CacheMiddleware(cache_alias=None, key_prefix=None) + + self.assertEquals(as_view_decorator.cache_timeout, 300) # Timeout value for 'default' cache, i.e. 300 + self.assertEquals(as_view_decorator.key_prefix, '') + self.assertEquals(as_view_decorator.cache_alias, 'default') # Value of DEFAULT_CACHE_ALIAS from django.core.cache + self.assertEquals(as_view_decorator.cache_anonymous_only, False) + + # Next, test with custom values: + as_view_decorator_with_custom = CacheMiddleware(cache_anonymous_only=True, cache_timeout=60, cache_alias='other', key_prefix='foo') + + self.assertEquals(as_view_decorator_with_custom.cache_timeout, 60) + self.assertEquals(as_view_decorator_with_custom.key_prefix, 'foo') + self.assertEquals(as_view_decorator_with_custom.cache_alias, 'other') + self.assertEquals(as_view_decorator_with_custom.cache_anonymous_only, True) + def test_middleware(self): def view(request, value): return HttpResponse('Hello World %s' % value) @@ -1201,6 +1239,7 @@ class CacheMiddlewareTest(unittest.TestCase): other_view = cache_page(cache='other')(view) other_with_prefix_view = cache_page(cache='other', key_prefix='prefix2')(view) + other_with_timeout_view = cache_page(4, cache='other', key_prefix='prefix3')(view) factory = RequestFactory() request = factory.get('/view/') @@ -1241,33 +1280,48 @@ class CacheMiddlewareTest(unittest.TestCase): response = other_with_prefix_view(request, '9') self.assertEquals(response.content, 'Hello World 9') + # Request from the alternate cache with a new prefix and a custom timeout + response = other_with_timeout_view(request, '10') + self.assertEquals(response.content, 'Hello World 10') + # But if we wait a couple of seconds... time.sleep(2) # ... the default cache will still hit cache = get_cache('default') - response = default_view(request, '10') + response = default_view(request, '11') self.assertEquals(response.content, 'Hello World 1') # ... the default cache with a prefix will still hit - response = default_with_prefix_view(request, '11') + response = default_with_prefix_view(request, '12') self.assertEquals(response.content, 'Hello World 4') # ... the explicit default cache will still hit - response = explicit_default_view(request, '12') + response = explicit_default_view(request, '13') self.assertEquals(response.content, 'Hello World 1') # ... the explicit default cache with a prefix will still hit - response = explicit_default_with_prefix_view(request, '13') + response = explicit_default_with_prefix_view(request, '14') self.assertEquals(response.content, 'Hello World 4') # .. but a rapidly expiring cache won't hit - response = other_view(request, '14') - self.assertEquals(response.content, 'Hello World 14') + response = other_view(request, '15') + self.assertEquals(response.content, 'Hello World 15') # .. even if it has a prefix - response = other_with_prefix_view(request, '15') - self.assertEquals(response.content, 'Hello World 15') + response = other_with_prefix_view(request, '16') + self.assertEquals(response.content, 'Hello World 16') + + # ... but a view with a custom timeout will still hit + response = other_with_timeout_view(request, '17') + self.assertEquals(response.content, 'Hello World 10') + + # And if we wait a few more seconds + time.sleep(2) + + # the custom timeouot cache will miss + response = other_with_timeout_view(request, '18') + self.assertEquals(response.content, 'Hello World 18') if __name__ == '__main__': unittest.main()