Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Fixed #19253 -- Extracted template cache key building logic

Introduced a public function
django.core.cache.utils.make_template_fragment_key
Thanks @chrismedrela for fruitful cooperation.
  • Loading branch information...
commit 99edbe0e279166db82caaf545ef92d5446a6a07e 1 parent b9cc610
Tomasz Paczkowski authored February 24, 2013 HonzaKral committed February 24, 2013
2  AUTHORS
@@ -382,6 +382,7 @@ answer newbie questions, and generally made Django that much better:
382 382
     Paul McLanahan <paul@mclanahan.net>
383 383
     Tobias McNulty <http://www.caktusgroup.com/blog>
384 384
     Andrews Medina <andrewsmedina@gmail.com>
  385
+    Christoph Mędrela <chris.medrela@gmail.com>
385 386
     Zain Memon
386 387
     Christian Metts
387 388
     michal@plovarna.cz
@@ -418,6 +419,7 @@ answer newbie questions, and generally made Django that much better:
418 419
     Christian Oudard <christian.oudard@gmail.com>
419 420
     oggie rob <oz.robharvey@gmail.com>
420 421
     oggy <ognjen.maric@gmail.com>
  422
+    Tomek Paczkowski <tomek@hauru.eu>
421 423
     Jens Page
422 424
     Jay Parlar <parlar@gmail.com>
423 425
     Carlos Eduardo de Paula <carlosedp@gmail.com>
15  django/core/cache/utils.py
... ...
@@ -0,0 +1,15 @@
  1
+from __future__ import absolute_import, unicode_literals
  2
+
  3
+import hashlib
  4
+from django.utils.encoding import force_bytes
  5
+from django.utils.http import urlquote
  6
+
  7
+TEMPLATE_FRAGMENT_KEY_TEMPLATE = 'template.cache.%s.%s'
  8
+
  9
+
  10
+def make_template_fragment_key(fragment_name, vary_on=None):
  11
+    if vary_on is None:
  12
+        vary_on = ()
  13
+    key = ':'.join([urlquote(var) for var in vary_on])
  14
+    args = hashlib.md5(force_bytes(key))
  15
+    return TEMPLATE_FRAGMENT_KEY_TEMPLATE % (fragment_name, args.hexdigest())
10  django/templatetags/cache.py
... ...
@@ -1,10 +1,8 @@
1 1
 from __future__ import unicode_literals
2 2
 
3  
-import hashlib
  3
+from django.core.cache.utils import make_template_fragment_key
4 4
 from django.template import Library, Node, TemplateSyntaxError, VariableDoesNotExist
5 5
 from django.core.cache import cache
6  
-from django.utils.encoding import force_bytes
7  
-from django.utils.http import urlquote
8 6
 
9 7
 register = Library()
10 8
 
@@ -24,10 +22,8 @@ def render(self, context):
24 22
             expire_time = int(expire_time)
25 23
         except (ValueError, TypeError):
26 24
             raise TemplateSyntaxError('"cache" tag got a non-integer timeout value: %r' % expire_time)
27  
-        # Build a key for this fragment and all vary-on's.
28  
-        key = ':'.join([urlquote(var.resolve(context)) for var in self.vary_on])
29  
-        args = hashlib.md5(force_bytes(key))
30  
-        cache_key = 'template.cache.%s.%s' % (self.fragment_name, args.hexdigest())
  25
+        vary_on = [var.resolve(context) for var in self.vary_on]
  26
+        cache_key = make_template_fragment_key(self.fragment_name, vary_on)
31 27
         value = cache.get(cache_key)
32 28
         if value is None:
33 29
             value = self.nodelist.render(context)
17  docs/topics/cache.txt
@@ -639,6 +639,23 @@ equivalent:
639 639
 This feature is useful in avoiding repetition in templates. You can set the
640 640
 timeout in a variable, in one place, and just reuse that value.
641 641
 
  642
+.. function:: django.core.cache.utils.make_template_fragment_key(fragment_name, vary_on=None)
  643
+
  644
+If you want to obtain the cache key used for a cached fragment, you can use
  645
+``make_template_fragment_key``. ``fragment_name`` is the same as second argument
  646
+to the ``cache`` template tag; ``vary_on`` is a list of all additional arguments
  647
+passed to the tag. This function can be useful for invalidating or overwriting
  648
+a cached item, for example:
  649
+
  650
+.. code-block:: python
  651
+
  652
+    >>> from django.core.cache import cache
  653
+    >>> from django.core.cache.utils import make_template_fragment_key
  654
+    # cache key for {% cache 500 sidebar username %}
  655
+    >>> key = make_template_fragment_key('sidebar', [username])
  656
+    >>> cache.delete(key) # invalidates cached template fragment
  657
+
  658
+
642 659
 The low-level cache API
643 660
 =======================
644 661
 
23  tests/regressiontests/cache/tests.py
@@ -20,6 +20,7 @@
20 20
 from django.core.cache.backends.base import (CacheKeyWarning,
21 21
     InvalidCacheBackendError)
22 22
 from django.db import router, transaction
  23
+from django.core.cache.utils import make_template_fragment_key
23 24
 from django.http import (HttpResponse, HttpRequest, StreamingHttpResponse,
24 25
     QueryDict)
25 26
 from django.middleware.cache import (FetchFromCacheMiddleware,
@@ -1809,3 +1810,25 @@ def test_admin(self):
1809 1810
             response = self.client.get('/test_admin/admin/')
1810 1811
             self.assertEqual(response.status_code, 200)
1811 1812
             self.assertTrue(response.has_header('ETag'))
  1813
+
  1814
+
  1815
+class TestMakeTemplateFragmentKey(TestCase):
  1816
+    def test_without_vary_on(self):
  1817
+        key = make_template_fragment_key('a.fragment')
  1818
+        self.assertEqual(key, 'template.cache.a.fragment.d41d8cd98f00b204e9800998ecf8427e')
  1819
+
  1820
+    def test_with_one_vary_on(self):
  1821
+        key = make_template_fragment_key('foo', ['abc'])
  1822
+        self.assertEqual(key,
  1823
+            'template.cache.foo.900150983cd24fb0d6963f7d28e17f72')
  1824
+
  1825
+    def test_with_many_vary_on(self):
  1826
+        key = make_template_fragment_key('bar', ['abc', 'def'])
  1827
+        self.assertEqual(key,
  1828
+            'template.cache.bar.4b35f12ab03cec09beec4c21b2d2fa88')
  1829
+
  1830
+    def test_proper_escaping(self):
  1831
+        key = make_template_fragment_key('spam', ['abc:def%'])
  1832
+        self.assertEqual(key,
  1833
+            'template.cache.spam.f27688177baec990cdf3fbd9d9c3f469')
  1834
+

0 notes on commit 99edbe0

Please sign in to comment.
Something went wrong with that request. Please try again.