summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--AUTHORS2
-rw-r--r--django/utils/cache.py18
-rw-r--r--docs/topics/cache.txt7
-rw-r--r--tests/regressiontests/cache/tests.py101
4 files changed, 121 insertions, 7 deletions
diff --git a/AUTHORS b/AUTHORS
index 4b5fc953b8..62dbeb1161 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -34,6 +34,7 @@ answer newbie questions, and generally made Django that much better:
Marty Alchin <gulopine@gamemusic.org>
Ahmad Alhashemi <trans@ahmadh.com>
Ahmad Al-Ibrahim
+ Antoni Aloy
Daniel Alves Barbosa de Oliveira Vaz <danielvaz@gmail.com>
AgarFu <heaven@croasanaso.sytes.net>
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/>
Matt McClanahan <http://mmcc.cx/>
Stanislaus Madueke
+ Yann Malet
Frantisek Malina <vizualbod@vizualbod.com>
Mike Malone <mjmalone@gmail.com>
Martin Maney <http://www.chipy.org/Martin_Maney>
diff --git a/django/utils/cache.py b/django/utils/cache.py
index 3c40e17e90..9828556057 100644
--- a/django/utils/cache.py
+++ b/django/utils/cache.py
@@ -19,16 +19,13 @@ An example: i18n middleware would need to distinguish caches by the
import re
import time
-try:
- set
-except NameError:
- from sets import Set as set # Python 2.3 fallback
from django.conf import settings
from django.core.cache import cache
from django.utils.encoding import smart_str, iri_to_uri
from django.utils.http import http_date
from django.utils.hashcompat import md5_constructor
+from django.utils import translation
from django.http import HttpRequest
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:
ctx.update(value)
path = md5_constructor(iri_to_uri(request.path))
- return 'views.decorators.cache.cache_page.%s.%s.%s' % (
- key_prefix, path.hexdigest(), ctx.hexdigest())
+ cache_key = 'views.decorators.cache.cache_page.%s.%s.%s' % (
+ 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):
"""Returns a cache key for the header cache."""
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):
"""
diff --git a/docs/topics/cache.txt b/docs/topics/cache.txt
index f8c9870462..dc450ae1fc 100644
--- a/docs/topics/cache.txt
+++ b/docs/topics/cache.txt
@@ -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
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`_
The per-view cache
diff --git a/tests/regressiontests/cache/tests.py b/tests/regressiontests/cache/tests.py
index 5d8d039cf5..83422b3a97 100644
--- a/tests/regressiontests/cache/tests.py
+++ b/tests/regressiontests/cache/tests.py
@@ -14,6 +14,8 @@ from django.core import management
from django.core.cache import get_cache
from django.core.cache.backends.base import InvalidCacheBackendError
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.hashcompat import md5_constructor
from regressiontests.cache.models import Poll, expensive_calculation
@@ -401,12 +403,15 @@ class CacheUtils(unittest.TestCase):
self.path = '/cache/test/'
self.old_settings_key_prefix = settings.CACHE_MIDDLEWARE_KEY_PREFIX
self.old_middleware_seconds = settings.CACHE_MIDDLEWARE_SECONDS
+ self.orig_use_i18n = settings.USE_I18N
settings.CACHE_MIDDLEWARE_KEY_PREFIX = 'settingsprefix'
settings.CACHE_MIDDLEWARE_SECONDS = 1
+ settings.USE_I18N = False
def tearDown(self):
settings.CACHE_MIDDLEWARE_KEY_PREFIX = self.old_settings_key_prefix
settings.CACHE_MIDDLEWARE_SECONDS = self.old_middleware_seconds
+ settings.USE_I18N = self.orig_use_i18n
def _get_request(self, path):
request = HttpRequest()
@@ -458,5 +463,101 @@ class CacheUtils(unittest.TestCase):
learn_cache_key(request, response)
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__':
unittest.main()