Code

Ticket #13014: 13014.diff

File 13014.diff, 5.8 KB (added by SmileyChris, 4 years ago)
Line 
1diff --git a/django/templatetags/cache.py b/django/templatetags/cache.py
2index 387dd87..1b1b2be 100644
3--- a/django/templatetags/cache.py
4+++ b/django/templatetags/cache.py
5@@ -1,9 +1,7 @@
6 from django.template import Library, Node, TemplateSyntaxError, Variable, VariableDoesNotExist
7 from django.template import resolve_variable
8 from django.core.cache import cache
9-from django.utils.encoding import force_unicode
10-from django.utils.http import urlquote
11-from django.utils.hashcompat import md5_constructor
12+from django.utils.cache import get_template_cache_key
13 
14 register = Library()
15 
16@@ -24,8 +22,8 @@ class CacheNode(Node):
17         except (ValueError, TypeError):
18             raise TemplateSyntaxError('"cache" tag got a non-integer timeout value: %r' % expire_time)
19         # Build a unicode key for this fragment and all vary-on's.
20-        args = md5_constructor(u':'.join([urlquote(resolve_variable(var, context)) for var in self.vary_on]))
21-        cache_key = 'template.cache.%s.%s' % (self.fragment_name, args.hexdigest())
22+        args = [resolve_variable(var, context) for var in self.vary_on]
23+        cache_key = get_template_cache_key(self.fragment_name, args)
24         value = cache.get(cache_key)
25         if value is None:
26             value = self.nodelist.render(context)
27diff --git a/django/utils/cache.py b/django/utils/cache.py
28index 6cfd893..4c360f6 100644
29--- a/django/utils/cache.py
30+++ b/django/utils/cache.py
31@@ -23,10 +23,9 @@ import time
32 from django.conf import settings
33 from django.core.cache import cache
34 from django.utils.encoding import smart_str, iri_to_uri
35-from django.utils.http import http_date
36+from django.utils.http import http_date, urlquote
37 from django.utils.hashcompat import md5_constructor
38 from django.utils.translation import get_language
39-from django.http import HttpRequest
40 
41 cc_delim_re = re.compile(r'\s*,\s*')
42 
43@@ -135,7 +134,14 @@ def patch_vary_headers(response, newheaders):
44     response['Vary'] = ', '.join(vary_headers + additional_headers)
45 
46 def _i18n_cache_key_suffix(request, cache_key):
47-    """If enabled, returns the cache key ending with a locale."""
48+    """
49+    If I18N is enabled, returns the cache key appended with a locale (otherwise
50+    returns the cache key unmodified).
51+
52+    While ``request`` is a required argument, if it does not make sense in the
53+    context of the key generation, use ``None`` for its value.
54+
55+    """
56     if settings.USE_I18N:
57         # first check if LocaleMiddleware or another middleware added
58         # LANGUAGE_CODE to request, then fall back to the active language
59@@ -210,6 +216,12 @@ def learn_cache_key(request, response, cache_timeout=None, key_prefix=None):
60         cache.set(cache_key, [], cache_timeout)
61         return _generate_cache_key(request, [], key_prefix)
62 
63+def get_template_cache_key(name, args=None):
64+    """Returns a cache key for a template tag related cache."""
65+    args = args and [urlquote(arg) for arg in args] or []
66+    md5_args = md5_constructor(u':'.join(args))
67+    cache_key = 'template.cache.%s.%s' % (name, md5_args.hexdigest())
68+    return _i18n_cache_key_suffix(request=None, cache_key=cache_key)
69 
70 def _to_tuple(s):
71     t = s.split('=',1)
72diff --git a/tests/regressiontests/cache/tests.py b/tests/regressiontests/cache/tests.py
73index 109374c..09ce616 100644
74--- a/tests/regressiontests/cache/tests.py
75+++ b/tests/regressiontests/cache/tests.py
76@@ -16,8 +16,11 @@ from django.core.cache.backends.base import InvalidCacheBackendError
77 from django.http import HttpResponse, HttpRequest
78 from django.middleware.cache import FetchFromCacheMiddleware, UpdateCacheMiddleware
79 from django.utils import translation
80-from django.utils.cache import patch_vary_headers, get_cache_key, learn_cache_key
81+from django.utils.cache import patch_vary_headers, get_cache_key, learn_cache_key,\
82+    get_template_cache_key
83 from django.utils.hashcompat import md5_constructor
84+from django.template import Context
85+from django.template.loader import get_template_from_string
86 from regressiontests.cache.models import Poll, expensive_calculation
87 
88 # functions/classes for complex data type tests
89@@ -527,7 +530,7 @@ class CacheI18nTest(unittest.TestCase):
90         key2 = get_cache_key(request)
91         self.assertEqual(key, key2)
92 
93-    def test_cache_key_no_i18n (self):
94+    def test_cache_key_no_i18n(self):
95         settings.USE_I18N = False
96         request = self._get_request()
97         lang = translation.get_language()
98@@ -568,5 +571,35 @@ class CacheI18nTest(unittest.TestCase):
99         get_cache_data = FetchFromCacheMiddleware().process_request(request)
100         self.assertEqual(get_cache_data.content, es_message)
101 
102+    def test_template_cache_key_i18n(self):
103+        settings.USE_I18N = True
104+        lang = 'en'
105+        translation.activate(lang)
106+        key = get_template_cache_key('somekey')
107+        self.assertTrue(key.endswith(lang), "Cache keys should include the "
108+                        "language name when i18n is active")
109+
110+    def test_template_cache_key_no_i18n(self):
111+        settings.USE_I18N = False
112+        lang = 'en'
113+        translation.activate(lang)
114+        key = get_template_cache_key('somekey')
115+        self.assertFalse(key.endswith(lang), "Cache keys shouldn't include "
116+                         "the language name when i18n is inactive")
117+
118+    def test_template_tag(self):
119+        settings.USE_I18N = True
120+        template = get_template_from_string('{% load cache %}'
121+                    '{% cache 60 greeting %}{{ welcome }}!{% endcache %}')
122+        translation.activate('en')
123+        template.render(Context({'welcome': 'Hello'}))
124+        translation.activate('es')
125+        template.render(Context({'welcome': 'Hola'}))
126+
127+        translation.activate('en')
128+        self.assertEqual(template.render(Context()), 'Hello!')
129+        translation.activate('es')
130+        self.assertEqual(template.render(Context()), 'Hola!')
131+
132 if __name__ == '__main__':
133     unittest.main()