Commit 2164e138 authored by Jannis Leidel's avatar Jannis Leidel
Browse files

Fixed #5691 - Adds the active language to the cache key. Thanks, Antoni Aloy,...

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
parent 6ba5fb37
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -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>
+11 −7
Original line number Diff line number Diff line
@@ -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' % (
    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):
    """
+7 −0
Original line number Diff line number Diff line
@@ -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
+101 −0
Original line number Diff line number Diff line
@@ -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()