Ticket #5691: patch_cache_i18n.patch

File patch_cache_i18n.patch, 14.5 KB (added by aaloy, 15 years ago)

patch and tests for cache i18n key generation

  • django/utils/cache.py

     
    2929from django.utils.encoding import smart_str, iri_to_uri
    3030from django.utils.http import http_date
    3131from django.utils.hashcompat import md5_constructor
     32from django.utils import translation
    3233
    3334cc_delim_re = re.compile(r'\s*,\s*')
    3435
     
    136137                          if newheader.lower() not in existing_headers]
    137138    response['Vary'] = ', '.join(vary_headers + additional_headers)
    138139
    139 def _generate_cache_key(request, headerlist, key_prefix):
     140def _generate_cache_key(request, headerlist, key_prefix):   
    140141    """Returns a cache key from the headers given in the header list."""
    141142    ctx = md5_constructor()
    142143    for header in headerlist:
    143144        value = request.META.get(header, None)
    144145        if value is not None:
    145146            ctx.update(value)
    146     return 'views.decorators.cache.cache_page.%s.%s.%s' % (
     147    cache_key = 'views.decorators.cache.cache_page.%s.%s.%s' % (
    147148               key_prefix, iri_to_uri(request.path), ctx.hexdigest())
    148149
     150    if settings.USE_I18N:
     151        cache_key += ".%s" % translation.get_language()
     152    return cache_key
     153
     154
    149155def get_cache_key(request, key_prefix=None):
    150156    """
    151157    Returns a cache key based on the request path. It can be used in the
     
    155161
    156162    If there is no headerlist stored, the page needs to be rebuilt, so this
    157163    function returns None.
    158     """
     164    """   
    159165    if key_prefix is None:
    160166        key_prefix = settings.CACHE_MIDDLEWARE_KEY_PREFIX
    161167    cache_key = 'views.decorators.cache.cache_header.%s.%s' % (
    162168                    key_prefix, iri_to_uri(request.path))
     169    if settings.USE_I18N:
     170        cache_key += ".%s" % translation.get_language()
     171 
    163172    headerlist = cache.get(cache_key, None)
    164173    if headerlist is not None:
    165174        return _generate_cache_key(request, headerlist, key_prefix)
     
    183192        key_prefix = settings.CACHE_MIDDLEWARE_KEY_PREFIX
    184193    if cache_timeout is None:
    185194        cache_timeout = settings.CACHE_MIDDLEWARE_SECONDS
     195
    186196    cache_key = 'views.decorators.cache.cache_header.%s.%s' % (
    187                     key_prefix, iri_to_uri(request.path))
     197                    key_prefix, iri_to_uri(request.path))   
     198    if settings.USE_I18N:
     199        cache_key += ".%s" % translation.get_language()
     200       
    188201    if response.has_header('Vary'):
    189202        headerlist = ['HTTP_'+header.upper().replace('-', '_')
    190203                      for header in cc_delim_re.split(response['Vary'])]
  • django/middleware/cache.py

     
    6868
    6969    def process_response(self, request, response):
    7070        """Sets the cache, if needed."""
     71
    7172        if not hasattr(request, '_cache_update_cache') or not request._cache_update_cache:
    7273            # We don't need to update the cache, just return.
    7374            return response
  • tests/regressiontests/cachei18n/views.py

    Property changes on: tests/regressiontests/cachei18n
    ___________________________________________________________________
    Added: svn:ignore
       + __init__.pyc
    
    
     
     1#/usr/bin/env python
     2# -*- coding: UTF-8 -*-
     3from django.shortcuts import render_to_response
     4from django.views.decorators.cache import cache_page
     5
     6RECORDS_PER_PAGE=2
     7VISIBLE_PAGES=3
     8
     9@cache_page(3600)
     10def app_index(request, page=1):
     11    "Home page with pagination. Adapted to the trunk version of paginator"
     12    data['content'] = "this is a test"   
     13    response = render_to_response('agenda/index.html',data)
     14    return response
     15
     16
     17
     18
  • tests/regressiontests/cachei18n/__init__.py

     
     1__author__="aaloy"
     2__date__ ="$21/11/2008 09:55:21$"
     3 No newline at end of file
  • tests/regressiontests/cachei18n/settings.py

     
     1# Django settings for test2 project.
     2
     3DEBUG = True
     4TEMPLATE_DEBUG = DEBUG
     5
     6ADMINS = (
     7    # ('Your Name', 'your_email@domain.com'),
     8)
     9
     10MANAGERS = ADMINS
     11
     12DATABASE_ENGINE = 'sqlite3'           # 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'oracle'.
     13DATABASE_NAME = '/tmp/test.sqlite'             # Or path to database file if using sqlite3.
     14DATABASE_USER = ''             # Not used with sqlite3.
     15DATABASE_PASSWORD = ''         # Not used with sqlite3.
     16DATABASE_HOST = ''             # Set to empty string for localhost. Not used with sqlite3.
     17DATABASE_PORT = ''             # Set to empty string for default. Not used with sqlite3.
     18
     19# Local time zone for this installation. Choices can be found here:
     20# http://en.wikipedia.org/wiki/List_of_tz_zones_by_name
     21# although not all choices may be available on all operating systems.
     22# If running in a Windows environment this must be set to the same as your
     23# system time zone.
     24TIME_ZONE = 'America/Chicago'
     25
     26# Language code for this installation. All choices can be found here:
     27# http://www.i18nguy.com/unicode/language-identifiers.html
     28LANGUAGE_CODE = 'en-us'
     29
     30SITE_ID = 1
     31
     32# If you set this to False, Django will make some optimizations so as not
     33# to load the internationalization machinery.
     34USE_I18N = True
     35
     36# Absolute path to the directory that holds media.
     37# Example: "/home/media/media.lawrence.com/"
     38MEDIA_ROOT = ''
     39
     40# URL that handles the media served from MEDIA_ROOT. Make sure to use a
     41# trailing slash if there is a path component (optional in other cases).
     42# Examples: "http://media.lawrence.com", "http://example.com/media/"
     43MEDIA_URL = ''
     44
     45# URL prefix for admin media -- CSS, JavaScript and images. Make sure to use a
     46# trailing slash.
     47# Examples: "http://foo.com/media/", "/media/".
     48ADMIN_MEDIA_PREFIX = '/media/'
     49
     50# Make this unique, and don't share it with anybody.
     51SECRET_KEY = 'il_uk6kwtuj4&(n$o*u-2x$k+f54r02)*zw+b+sx_g%puw6@b('
     52
     53# List of callables that know how to import templates from various sources.
     54TEMPLATE_LOADERS = (
     55    'django.template.loaders.filesystem.load_template_source',
     56    'django.template.loaders.app_directories.load_template_source',
     57#     'django.template.loaders.eggs.load_template_source',
     58)
     59
     60MIDDLEWARE_CLASSES = (
     61    'django.middleware.common.CommonMiddleware',   
     62    'django.contrib.sessions.middleware.SessionMiddleware',
     63    'django.middleware.locale.LocaleMiddleware',
     64    'django.contrib.auth.middleware.AuthenticationMiddleware',
     65)
     66
     67ROOT_URLCONF = 'test2.urls'
     68
     69TEMPLATE_DIRS = (
     70    # Put strings here, like "/home/html/django_templates" or "C:/www/django/templates".
     71    # Always use forward slashes, even on Windows.
     72    # Don't forget to use absolute paths, not relative paths.
     73)
     74
     75INSTALLED_APPS = (
     76    'django.contrib.auth',
     77    'django.contrib.contenttypes',
     78    'django.contrib.sessions',
     79    'django.contrib.sites',
     80)
     81
     82LANGUAGES = (
     83    ('en', 'English'),
     84    ('es', 'Spanish'),
     85)
     86
  • tests/regressiontests/cachei18n/tests.py

     
     1# -*- coding: UTF-8 -*-
     2
     3from django.core.cache import cache
     4from django.core.cache import get_cache
     5from django.core.cache.backends.filebased import CacheClass as FileCache
     6from django.http import HttpRequest
     7from django.http import HttpResponse
     8from django.utils import cache
     9from django.utils import translation
     10
     11import shutil
     12import tempfile
     13import unittest
     14from django.conf import settings
     15from django.middleware.cache import FetchFromCacheMiddleware, UpdateCacheMiddleware
     16
     17
     18
     19
     20class Cache(unittest.TestCase):
     21    def setUp(self):
     22        # Special-case the file cache so we can clean up after ourselves.
     23        if isinstance(cache, FileCache):
     24            self.cache_dir = tempfile.mkdtemp()
     25            self.cache = get_cache("file:///%s" % self.cache_dir)
     26        else:
     27            self.cache_dir = None
     28            self.cache = cache
     29        settings.LANGUAGES = (
     30                ('en', 'English'),
     31                ('es', 'Spanish'),
     32        )
     33
     34    def tearDown(self):
     35        if self.cache_dir is not None:
     36            shutil.rmtree(self.cache_dir)
     37
     38    def _get_request(self):
     39        request = HttpRequest()
     40        request.META = {
     41            'SERVER_NAME': 'testserver',
     42            'SERVER_PORT': 80,
     43        }
     44        request.path = request.path_info = "/agenda/index/"
     45        return request
     46
     47    def _get_request_cache(self):
     48        request = HttpRequest()
     49        request.META = {
     50            'SERVER_NAME': 'testserver',
     51            'SERVER_PORT': 80,
     52        }
     53        request.path = request.path_info = "/agenda/index/"
     54        request._cache_update_cache = True
     55        request.method = 'GET'
     56        request.session = {}
     57        return request
     58
     59
     60
     61    def test_cache_key_i18n(self):
     62        settings.USE_I18N = True
     63        request = self._get_request()
     64        lang = translation.get_language()
     65        response = HttpResponse()
     66        key = cache.learn_cache_key(request, response)
     67        self.assertTrue(key.endswith(lang), "Keys does not use the language")
     68        key2 = cache.get_cache_key(request)       
     69        self.assertEqual(key, key2)
     70
     71    def test_cache_key_not_i18n (self):
     72        settings.USE_I18N = False
     73        request = self._get_request()
     74        lang = translation.get_language()
     75        response = HttpResponse()
     76        key = cache.learn_cache_key(request, response)
     77        self.assertFalse(key.endswith(lang), "Keys does not use the language")
     78
     79    def test_middleware(self):
     80
     81        def set_cache(request, lang, msg):
     82            translation.activate(lang)
     83            response = HttpResponse()
     84            response.content= msg
     85            return UpdateCacheMiddleware().process_response(request, response)
     86
     87        settings.CACHE_MIDDLEWARE_SECONDS = 60
     88        settings.CACHE_MIDDLEWARE_KEY_PREFIX="test"
     89        settings.CACHE_BACKEND='locmem:///'
     90        settings.USE_I18N = True
     91        en_message ="Hello world!"
     92        es_message ="Hola mundo!"
     93
     94        request = self._get_request_cache()
     95        set_cache(request, 'en', en_message)
     96        get_cache_data = FetchFromCacheMiddleware().process_request(request)
     97        # Check that we can recover the cache
     98        self.assertNotEqual(get_cache_data.content, None)
     99        self.assertEqual(en_message, get_cache_data.content)
     100        # change the session language and set content
     101        request = self._get_request_cache()
     102        set_cache(request, 'es', es_message)
     103        # change again the language
     104        translation.activate('en')
     105        # retrieve the content from cache
     106        get_cache_data = FetchFromCacheMiddleware().process_request(request)
     107        self.assertEqual(get_cache_data.content, en_message)
     108        # change again the language
     109        translation.activate('es')
     110        get_cache_data = FetchFromCacheMiddleware().process_request(request)
     111        self.assertEqual(get_cache_data.content, es_message)
     112
     113
     114if __name__ == '__main__':
     115    unittest.main()
  • tests/regressiontests/cachei18n/models.py

     
     1# -*- coding: UTF-8 -*-
     2__doc__ = """Defines de application model"""
     3
     4from django.db import models
     5
     6
     7class Person (models.Model):
     8    "Defines the model for the person entity"
     9    first_name = models.CharField(max_length=30)
     10    last_name = models.CharField(max_length=30)
     11    phone = models.CharField(max_length=20)
     12    age = models.IntegerField()
     13    comments = models.TextField()
     14
     15    def __unicode__(self):
     16        return u'%s %s' % (self.first_name, self.last_name)
     17
     18
  • tests/regressiontests/cachei18n/urls.py

     
     1from django.conf.urls.defaults import *
     2from django.conf import settings
     3from django.contrib import admin
     4from django.views.generic.simple import direct_to_template
     5
     6admin.autodiscover()
     7
     8urlpatterns = patterns('',
     9     # our agenda application
     10     (r'^$',direct_to_template, {'template': 'index.html'}),
     11     (r'^appindex/$', 'views.appindex')
     12     # Administration
     13     (r'^admin/doc/', include('django.contrib.admindocs.urls')),
     14     (r'^admin/(.*)', admin.site.root),
     15    )
     16
     17
     18# We're going to use the Django server in development, so we'll server
     19# also the estatic content.
     20if settings.DEBUG:
     21        urlpatterns += patterns('',
     22       (r'^media/(?P<path>.*)$', 'django.views.static.serve', {'document_root':'./media/'}),
     23    )
     24
     25
  • tests/regressiontests/cachei18n/templates/agenda/index.html

     
     1<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
     2<html xmlns="http://www.w3.org/1999/xhtml">
     3<head>
     4        <title>agenda title</title>
     5<link rel="stylesheet" type="text/css" href="/media/css/paginator.css" />
     6</head>
     7<body>
     8        <h1>{{ content }}</h1>
     9</body>
     10</html>
  • tests/regressiontests/cachei18n/templates/index.html

     
     1<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">   
     2<html xmlns="http://www.w3.org/1999/xhtml">
     3<head>
     4    <title>test title</title>
     5</head>
     6<body>
     7    <body>
     8        <p>This is a test page for cache purposes</p>
     9        <p><strong>Menu</strong></p>
     10    </body>
     11</html>
Back to Top