Fixed #5691 - Adds the active language to the cache key. Thanks, Antoni Aloy, Ramiro Morales and Yann Malet.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@12546 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
6ba5fb3728
commit
2164e138e3
2
AUTHORS
2
AUTHORS
|
@ -34,6 +34,7 @@ answer newbie questions, and generally made Django that much better:
|
||||||
Marty Alchin <gulopine@gamemusic.org>
|
Marty Alchin <gulopine@gamemusic.org>
|
||||||
Ahmad Alhashemi <trans@ahmadh.com>
|
Ahmad Alhashemi <trans@ahmadh.com>
|
||||||
Ahmad Al-Ibrahim
|
Ahmad Al-Ibrahim
|
||||||
|
Antoni Aloy
|
||||||
Daniel Alves Barbosa de Oliveira Vaz <danielvaz@gmail.com>
|
Daniel Alves Barbosa de Oliveira Vaz <danielvaz@gmail.com>
|
||||||
AgarFu <heaven@croasanaso.sytes.net>
|
AgarFu <heaven@croasanaso.sytes.net>
|
||||||
Dagur Páll Ammendrup <dagurp@gmail.com>
|
Dagur Páll Ammendrup <dagurp@gmail.com>
|
||||||
|
@ -301,6 +302,7 @@ answer newbie questions, and generally made Django that much better:
|
||||||
Martin Mahner <http://www.mahner.org/>
|
Martin Mahner <http://www.mahner.org/>
|
||||||
Matt McClanahan <http://mmcc.cx/>
|
Matt McClanahan <http://mmcc.cx/>
|
||||||
Stanislaus Madueke
|
Stanislaus Madueke
|
||||||
|
Yann Malet
|
||||||
Frantisek Malina <vizualbod@vizualbod.com>
|
Frantisek Malina <vizualbod@vizualbod.com>
|
||||||
Mike Malone <mjmalone@gmail.com>
|
Mike Malone <mjmalone@gmail.com>
|
||||||
Martin Maney <http://www.chipy.org/Martin_Maney>
|
Martin Maney <http://www.chipy.org/Martin_Maney>
|
||||||
|
|
|
@ -19,16 +19,13 @@ An example: i18n middleware would need to distinguish caches by the
|
||||||
|
|
||||||
import re
|
import re
|
||||||
import time
|
import time
|
||||||
try:
|
|
||||||
set
|
|
||||||
except NameError:
|
|
||||||
from sets import Set as set # Python 2.3 fallback
|
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.core.cache import cache
|
from django.core.cache import cache
|
||||||
from django.utils.encoding import smart_str, iri_to_uri
|
from django.utils.encoding import smart_str, iri_to_uri
|
||||||
from django.utils.http import http_date
|
from django.utils.http import http_date
|
||||||
from django.utils.hashcompat import md5_constructor
|
from django.utils.hashcompat import md5_constructor
|
||||||
|
from django.utils import translation
|
||||||
from django.http import HttpRequest
|
from django.http import HttpRequest
|
||||||
|
|
||||||
cc_delim_re = re.compile(r'\s*,\s*')
|
cc_delim_re = re.compile(r'\s*,\s*')
|
||||||
|
@ -145,13 +142,20 @@ def _generate_cache_key(request, headerlist, key_prefix):
|
||||||
if value is not None:
|
if value is not None:
|
||||||
ctx.update(value)
|
ctx.update(value)
|
||||||
path = md5_constructor(iri_to_uri(request.path))
|
path = md5_constructor(iri_to_uri(request.path))
|
||||||
return 'views.decorators.cache.cache_page.%s.%s.%s' % (
|
cache_key = 'views.decorators.cache.cache_page.%s.%s.%s' % (
|
||||||
key_prefix, path.hexdigest(), ctx.hexdigest())
|
key_prefix, path.hexdigest(), ctx.hexdigest())
|
||||||
|
if settings.USE_I18N:
|
||||||
|
cache_key += '.%s' % translation.get_language()
|
||||||
|
return cache_key
|
||||||
|
|
||||||
def _generate_cache_header_key(key_prefix, request):
|
def _generate_cache_header_key(key_prefix, request):
|
||||||
"""Returns a cache key for the header cache."""
|
"""Returns a cache key for the header cache."""
|
||||||
path = md5_constructor(iri_to_uri(request.path))
|
path = md5_constructor(iri_to_uri(request.path))
|
||||||
return 'views.decorators.cache.cache_header.%s.%s' % (key_prefix, path.hexdigest())
|
cache_key = 'views.decorators.cache.cache_header.%s.%s' % (
|
||||||
|
key_prefix, path.hexdigest())
|
||||||
|
if settings.USE_I18N:
|
||||||
|
cache_key += ".%s" % translation.get_language()
|
||||||
|
return cache_key
|
||||||
|
|
||||||
def get_cache_key(request, key_prefix=None):
|
def get_cache_key(request, key_prefix=None):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -320,6 +320,13 @@ time, rather than ``CACHE_MIDDLEWARE_SECONDS``. Using the decorators in
|
||||||
the ``never_cache`` decorator). See the `using other headers`__ section for
|
the ``never_cache`` decorator). See the `using other headers`__ section for
|
||||||
more on these decorators.
|
more on these decorators.
|
||||||
|
|
||||||
|
.. versionadded:: 1.2
|
||||||
|
|
||||||
|
If :setting:`USE_I18N` is set to ``True`` then the generated cache key will
|
||||||
|
include the name of the currently active :term:`language<language code>`.
|
||||||
|
This allows you to easily cache multilingual sites without having to create
|
||||||
|
the cache key yourself.
|
||||||
|
|
||||||
__ `Controlling cache: Using other headers`_
|
__ `Controlling cache: Using other headers`_
|
||||||
|
|
||||||
The per-view cache
|
The per-view cache
|
||||||
|
|
|
@ -14,6 +14,8 @@ from django.core import management
|
||||||
from django.core.cache import get_cache
|
from django.core.cache import get_cache
|
||||||
from django.core.cache.backends.base import InvalidCacheBackendError
|
from django.core.cache.backends.base import InvalidCacheBackendError
|
||||||
from django.http import HttpResponse, HttpRequest
|
from django.http import HttpResponse, HttpRequest
|
||||||
|
from django.middleware.cache import FetchFromCacheMiddleware, UpdateCacheMiddleware
|
||||||
|
from django.utils import translation
|
||||||
from django.utils.cache import patch_vary_headers, get_cache_key, learn_cache_key
|
from django.utils.cache import patch_vary_headers, get_cache_key, learn_cache_key
|
||||||
from django.utils.hashcompat import md5_constructor
|
from django.utils.hashcompat import md5_constructor
|
||||||
from regressiontests.cache.models import Poll, expensive_calculation
|
from regressiontests.cache.models import Poll, expensive_calculation
|
||||||
|
@ -401,12 +403,15 @@ class CacheUtils(unittest.TestCase):
|
||||||
self.path = '/cache/test/'
|
self.path = '/cache/test/'
|
||||||
self.old_settings_key_prefix = settings.CACHE_MIDDLEWARE_KEY_PREFIX
|
self.old_settings_key_prefix = settings.CACHE_MIDDLEWARE_KEY_PREFIX
|
||||||
self.old_middleware_seconds = settings.CACHE_MIDDLEWARE_SECONDS
|
self.old_middleware_seconds = settings.CACHE_MIDDLEWARE_SECONDS
|
||||||
|
self.orig_use_i18n = settings.USE_I18N
|
||||||
settings.CACHE_MIDDLEWARE_KEY_PREFIX = 'settingsprefix'
|
settings.CACHE_MIDDLEWARE_KEY_PREFIX = 'settingsprefix'
|
||||||
settings.CACHE_MIDDLEWARE_SECONDS = 1
|
settings.CACHE_MIDDLEWARE_SECONDS = 1
|
||||||
|
settings.USE_I18N = False
|
||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
settings.CACHE_MIDDLEWARE_KEY_PREFIX = self.old_settings_key_prefix
|
settings.CACHE_MIDDLEWARE_KEY_PREFIX = self.old_settings_key_prefix
|
||||||
settings.CACHE_MIDDLEWARE_SECONDS = self.old_middleware_seconds
|
settings.CACHE_MIDDLEWARE_SECONDS = self.old_middleware_seconds
|
||||||
|
settings.USE_I18N = self.orig_use_i18n
|
||||||
|
|
||||||
def _get_request(self, path):
|
def _get_request(self, path):
|
||||||
request = HttpRequest()
|
request = HttpRequest()
|
||||||
|
@ -458,5 +463,101 @@ class CacheUtils(unittest.TestCase):
|
||||||
learn_cache_key(request, response)
|
learn_cache_key(request, response)
|
||||||
self.assertEqual(get_cache_key(request), 'views.decorators.cache.cache_page.settingsprefix.a8c87a3d8c44853d7f79474f7ffe4ad5.d41d8cd98f00b204e9800998ecf8427e')
|
self.assertEqual(get_cache_key(request), 'views.decorators.cache.cache_page.settingsprefix.a8c87a3d8c44853d7f79474f7ffe4ad5.d41d8cd98f00b204e9800998ecf8427e')
|
||||||
|
|
||||||
|
class CacheI18nTest(unittest.TestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
self.orig_cache_middleware_seconds = settings.CACHE_MIDDLEWARE_SECONDS
|
||||||
|
self.orig_cache_middleware_key_prefix = settings.CACHE_MIDDLEWARE_KEY_PREFIX
|
||||||
|
self.orig_cache_backend = settings.CACHE_BACKEND
|
||||||
|
self.orig_use_i18n = settings.USE_I18N
|
||||||
|
self.orig_languages = settings.LANGUAGES
|
||||||
|
settings.LANGUAGES = (
|
||||||
|
('en', 'English'),
|
||||||
|
('es', 'Spanish'),
|
||||||
|
)
|
||||||
|
settings.CACHE_MIDDLEWARE_KEY_PREFIX = 'settingsprefix'
|
||||||
|
settings.CACHE_MIDDLEWARE_SECONDS
|
||||||
|
self.path = '/cache/test/'
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
settings.CACHE_MIDDLEWARE_SECONDS = self.orig_cache_middleware_seconds
|
||||||
|
settings.CACHE_MIDDLEWARE_KEY_PREFIX = self.orig_cache_middleware_key_prefix
|
||||||
|
settings.CACHE_BACKEND = self.orig_cache_backend
|
||||||
|
settings.USE_I18N = self.orig_use_i18n
|
||||||
|
settings.LANGUAGES = self.orig_languages
|
||||||
|
translation.deactivate()
|
||||||
|
|
||||||
|
def _get_request(self):
|
||||||
|
request = HttpRequest()
|
||||||
|
request.META = {
|
||||||
|
'SERVER_NAME': 'testserver',
|
||||||
|
'SERVER_PORT': 80,
|
||||||
|
}
|
||||||
|
request.path = request.path_info = self.path
|
||||||
|
return request
|
||||||
|
|
||||||
|
def _get_request_cache(self):
|
||||||
|
request = HttpRequest()
|
||||||
|
request.META = {
|
||||||
|
'SERVER_NAME': 'testserver',
|
||||||
|
'SERVER_PORT': 80,
|
||||||
|
}
|
||||||
|
request.path = request.path_info = self.path
|
||||||
|
request._cache_update_cache = True
|
||||||
|
request.method = 'GET'
|
||||||
|
request.session = {}
|
||||||
|
return request
|
||||||
|
|
||||||
|
def test_cache_key_i18n(self):
|
||||||
|
settings.USE_I18N = True
|
||||||
|
request = self._get_request()
|
||||||
|
lang = translation.get_language()
|
||||||
|
response = HttpResponse()
|
||||||
|
key = learn_cache_key(request, response)
|
||||||
|
self.assertTrue(key.endswith(lang), "Cache keys should include the language name when i18n is active")
|
||||||
|
key2 = get_cache_key(request)
|
||||||
|
self.assertEqual(key, key2)
|
||||||
|
|
||||||
|
def test_cache_key_no_i18n (self):
|
||||||
|
settings.USE_I18N = False
|
||||||
|
request = self._get_request()
|
||||||
|
lang = translation.get_language()
|
||||||
|
response = HttpResponse()
|
||||||
|
key = learn_cache_key(request, response)
|
||||||
|
self.assertFalse(key.endswith(lang), "Cache keys shouldn't include the language name when i18n is inactive")
|
||||||
|
|
||||||
|
def test_middleware(self):
|
||||||
|
def set_cache(request, lang, msg):
|
||||||
|
translation.activate(lang)
|
||||||
|
response = HttpResponse()
|
||||||
|
response.content= msg
|
||||||
|
return UpdateCacheMiddleware().process_response(request, response)
|
||||||
|
|
||||||
|
settings.CACHE_MIDDLEWARE_SECONDS = 60
|
||||||
|
settings.CACHE_MIDDLEWARE_KEY_PREFIX="test"
|
||||||
|
settings.CACHE_BACKEND='locmem:///'
|
||||||
|
settings.USE_I18N = True
|
||||||
|
en_message ="Hello world!"
|
||||||
|
es_message ="Hola mundo!"
|
||||||
|
|
||||||
|
request = self._get_request_cache()
|
||||||
|
set_cache(request, 'en', en_message)
|
||||||
|
get_cache_data = FetchFromCacheMiddleware().process_request(request)
|
||||||
|
# Check that we can recover the cache
|
||||||
|
self.assertNotEqual(get_cache_data.content, None)
|
||||||
|
self.assertEqual(en_message, get_cache_data.content)
|
||||||
|
# change the session language and set content
|
||||||
|
request = self._get_request_cache()
|
||||||
|
set_cache(request, 'es', es_message)
|
||||||
|
# change again the language
|
||||||
|
translation.activate('en')
|
||||||
|
# retrieve the content from cache
|
||||||
|
get_cache_data = FetchFromCacheMiddleware().process_request(request)
|
||||||
|
self.assertEqual(get_cache_data.content, en_message)
|
||||||
|
# change again the language
|
||||||
|
translation.activate('es')
|
||||||
|
get_cache_data = FetchFromCacheMiddleware().process_request(request)
|
||||||
|
self.assertEqual(get_cache_data.content, es_message)
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|
Loading…
Reference in New Issue