mirror of
https://github.com/django/django.git
synced 2025-05-30 02:36:29 +00:00
Fixed #15144 -- Corrected some problems with the Cache middleware when used with multiple cache settings. Thanks to Jim Dalton for the report, and to Jim and Joshua Ginsberg for the work on the patch.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@15285 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
4849ebb017
commit
fe581013b0
1
AUTHORS
1
AUTHORS
@ -129,6 +129,7 @@ answer newbie questions, and generally made Django that much better:
|
|||||||
Jure Cuhalev <gandalf@owca.info>
|
Jure Cuhalev <gandalf@owca.info>
|
||||||
John D'Agostino <john.dagostino@gmail.com>
|
John D'Agostino <john.dagostino@gmail.com>
|
||||||
dackze+django@gmail.com
|
dackze+django@gmail.com
|
||||||
|
Jim Dalton <jim.dalton@gmail.com>
|
||||||
Mihai Damian <yang_damian@yahoo.com>
|
Mihai Damian <yang_damian@yahoo.com>
|
||||||
David Danier <goliath.mailinglist@gmx.de>
|
David Danier <goliath.mailinglist@gmx.de>
|
||||||
Dirk Datzert <dummy@habmalnefrage.de>
|
Dirk Datzert <dummy@habmalnefrage.de>
|
||||||
|
1
django/core/cache/__init__.py
vendored
1
django/core/cache/__init__.py
vendored
@ -110,6 +110,7 @@ def parse_backend_conf(backend, **kwargs):
|
|||||||
conf = settings.CACHES.get(backend, None)
|
conf = settings.CACHES.get(backend, None)
|
||||||
if conf is not None:
|
if conf is not None:
|
||||||
args = conf.copy()
|
args = conf.copy()
|
||||||
|
args.update(kwargs)
|
||||||
backend = args.pop('BACKEND')
|
backend = args.pop('BACKEND')
|
||||||
location = args.pop('LOCATION', '')
|
location = args.pop('LOCATION', '')
|
||||||
return backend, location, args
|
return backend, location, args
|
||||||
|
@ -65,7 +65,8 @@ class UpdateCacheMiddleware(object):
|
|||||||
self.cache_timeout = settings.CACHE_MIDDLEWARE_SECONDS
|
self.cache_timeout = settings.CACHE_MIDDLEWARE_SECONDS
|
||||||
self.key_prefix = settings.CACHE_MIDDLEWARE_KEY_PREFIX
|
self.key_prefix = settings.CACHE_MIDDLEWARE_KEY_PREFIX
|
||||||
self.cache_anonymous_only = getattr(settings, 'CACHE_MIDDLEWARE_ANONYMOUS_ONLY', False)
|
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):
|
def process_response(self, request, response):
|
||||||
"""Sets the cache, if needed."""
|
"""Sets the cache, if needed."""
|
||||||
@ -101,7 +102,8 @@ class FetchFromCacheMiddleware(object):
|
|||||||
self.cache_timeout = settings.CACHE_MIDDLEWARE_SECONDS
|
self.cache_timeout = settings.CACHE_MIDDLEWARE_SECONDS
|
||||||
self.key_prefix = settings.CACHE_MIDDLEWARE_KEY_PREFIX
|
self.key_prefix = settings.CACHE_MIDDLEWARE_KEY_PREFIX
|
||||||
self.cache_anonymous_only = getattr(settings, 'CACHE_MIDDLEWARE_ANONYMOUS_ONLY', False)
|
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):
|
def process_request(self, request):
|
||||||
"""
|
"""
|
||||||
@ -152,8 +154,9 @@ class CacheMiddleware(UpdateCacheMiddleware, FetchFromCacheMiddleware):
|
|||||||
# we need to use middleware defaults.
|
# we need to use middleware defaults.
|
||||||
|
|
||||||
cache_kwargs = {}
|
cache_kwargs = {}
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self.key_prefix = kwargs.get('key_prefix')
|
self.key_prefix = kwargs['key_prefix']
|
||||||
if self.key_prefix is not None:
|
if self.key_prefix is not None:
|
||||||
cache_kwargs['KEY_PREFIX'] = self.key_prefix
|
cache_kwargs['KEY_PREFIX'] = self.key_prefix
|
||||||
else:
|
else:
|
||||||
@ -161,14 +164,15 @@ class CacheMiddleware(UpdateCacheMiddleware, FetchFromCacheMiddleware):
|
|||||||
except KeyError:
|
except KeyError:
|
||||||
self.key_prefix = settings.CACHE_MIDDLEWARE_KEY_PREFIX
|
self.key_prefix = settings.CACHE_MIDDLEWARE_KEY_PREFIX
|
||||||
cache_kwargs['KEY_PREFIX'] = self.key_prefix
|
cache_kwargs['KEY_PREFIX'] = self.key_prefix
|
||||||
|
|
||||||
try:
|
try:
|
||||||
cache_alias = kwargs.get('cache_alias')
|
self.cache_alias = kwargs['cache_alias']
|
||||||
if cache_alias is None:
|
if self.cache_alias is None:
|
||||||
cache_alias = DEFAULT_CACHE_ALIAS
|
self.cache_alias = DEFAULT_CACHE_ALIAS
|
||||||
if cache_timeout is not None:
|
if cache_timeout is not None:
|
||||||
cache_kwargs['TIMEOUT'] = cache_timeout
|
cache_kwargs['TIMEOUT'] = cache_timeout
|
||||||
except KeyError:
|
except KeyError:
|
||||||
cache_alias = settings.CACHE_MIDDLEWARE_ALIAS
|
self.cache_alias = settings.CACHE_MIDDLEWARE_ALIAS
|
||||||
if cache_timeout is None:
|
if cache_timeout is None:
|
||||||
cache_kwargs['TIMEOUT'] = settings.CACHE_MIDDLEWARE_SECONDS
|
cache_kwargs['TIMEOUT'] = settings.CACHE_MIDDLEWARE_SECONDS
|
||||||
else:
|
else:
|
||||||
@ -179,5 +183,5 @@ class CacheMiddleware(UpdateCacheMiddleware, FetchFromCacheMiddleware):
|
|||||||
else:
|
else:
|
||||||
self.cache_anonymous_only = cache_anonymous_only
|
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
|
self.cache_timeout = self.cache.default_timeout
|
||||||
|
70
tests/regressiontests/cache/tests.py
vendored
70
tests/regressiontests/cache/tests.py
vendored
@ -1133,10 +1133,14 @@ class CacheMiddlewareTest(unittest.TestCase):
|
|||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.orig_cache_middleware_alias = settings.CACHE_MIDDLEWARE_ALIAS
|
self.orig_cache_middleware_alias = settings.CACHE_MIDDLEWARE_ALIAS
|
||||||
self.orig_cache_middleware_key_prefix = settings.CACHE_MIDDLEWARE_KEY_PREFIX
|
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
|
self.orig_caches = settings.CACHES
|
||||||
|
|
||||||
settings.CACHE_MIDDLEWARE_ALIAS = 'other'
|
settings.CACHE_MIDDLEWARE_ALIAS = 'other'
|
||||||
settings.CACHE_MIDDLEWARE_KEY_PREFIX = 'middlewareprefix'
|
settings.CACHE_MIDDLEWARE_KEY_PREFIX = 'middlewareprefix'
|
||||||
|
settings.CACHE_MIDDLEWARE_SECONDS = 30
|
||||||
|
settings.CACHE_MIDDLEWARE_ANONYMOUS_ONLY = False
|
||||||
settings.CACHES = {
|
settings.CACHES = {
|
||||||
'default': {
|
'default': {
|
||||||
'BACKEND': 'django.core.cache.backends.locmem.LocMemCache'
|
'BACKEND': 'django.core.cache.backends.locmem.LocMemCache'
|
||||||
@ -1151,8 +1155,42 @@ class CacheMiddlewareTest(unittest.TestCase):
|
|||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
settings.CACHE_MIDDLEWARE_ALIAS = self.orig_cache_middleware_alias
|
settings.CACHE_MIDDLEWARE_ALIAS = self.orig_cache_middleware_alias
|
||||||
settings.CACHE_MIDDLEWARE_KEY_PREFIX = self.orig_cache_middleware_key_prefix
|
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
|
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 test_middleware(self):
|
||||||
def view(request, value):
|
def view(request, value):
|
||||||
return HttpResponse('Hello World %s' % value)
|
return HttpResponse('Hello World %s' % value)
|
||||||
@ -1201,6 +1239,7 @@ class CacheMiddlewareTest(unittest.TestCase):
|
|||||||
|
|
||||||
other_view = cache_page(cache='other')(view)
|
other_view = cache_page(cache='other')(view)
|
||||||
other_with_prefix_view = cache_page(cache='other', key_prefix='prefix2')(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()
|
factory = RequestFactory()
|
||||||
request = factory.get('/view/')
|
request = factory.get('/view/')
|
||||||
@ -1241,33 +1280,48 @@ class CacheMiddlewareTest(unittest.TestCase):
|
|||||||
response = other_with_prefix_view(request, '9')
|
response = other_with_prefix_view(request, '9')
|
||||||
self.assertEquals(response.content, 'Hello World 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...
|
# But if we wait a couple of seconds...
|
||||||
time.sleep(2)
|
time.sleep(2)
|
||||||
|
|
||||||
# ... the default cache will still hit
|
# ... the default cache will still hit
|
||||||
cache = get_cache('default')
|
cache = get_cache('default')
|
||||||
response = default_view(request, '10')
|
response = default_view(request, '11')
|
||||||
self.assertEquals(response.content, 'Hello World 1')
|
self.assertEquals(response.content, 'Hello World 1')
|
||||||
|
|
||||||
# ... the default cache with a prefix will still hit
|
# ... 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')
|
self.assertEquals(response.content, 'Hello World 4')
|
||||||
|
|
||||||
# ... the explicit default cache will still hit
|
# ... 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')
|
self.assertEquals(response.content, 'Hello World 1')
|
||||||
|
|
||||||
# ... the explicit default cache with a prefix will still hit
|
# ... 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')
|
self.assertEquals(response.content, 'Hello World 4')
|
||||||
|
|
||||||
# .. but a rapidly expiring cache won't hit
|
# .. but a rapidly expiring cache won't hit
|
||||||
response = other_view(request, '14')
|
response = other_view(request, '15')
|
||||||
self.assertEquals(response.content, 'Hello World 14')
|
self.assertEquals(response.content, 'Hello World 15')
|
||||||
|
|
||||||
# .. even if it has a prefix
|
# .. even if it has a prefix
|
||||||
response = other_with_prefix_view(request, '15')
|
response = other_with_prefix_view(request, '16')
|
||||||
self.assertEquals(response.content, 'Hello World 15')
|
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__':
|
if __name__ == '__main__':
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user