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:
Jannis Leidel 2010-02-23 20:45:28 +00:00
parent 6ba5fb3728
commit 2164e138e3
4 changed files with 121 additions and 7 deletions

View File

@ -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>

View File

@ -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):
""" """

View File

@ -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

View File

@ -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()