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.
This commit is contained in:
parent
b9cc61021a
commit
99edbe0e27
2
AUTHORS
2
AUTHORS
|
@ -382,6 +382,7 @@ answer newbie questions, and generally made Django that much better:
|
|||
Paul McLanahan <paul@mclanahan.net>
|
||||
Tobias McNulty <http://www.caktusgroup.com/blog>
|
||||
Andrews Medina <andrewsmedina@gmail.com>
|
||||
Christoph Mędrela <chris.medrela@gmail.com>
|
||||
Zain Memon
|
||||
Christian Metts
|
||||
michal@plovarna.cz
|
||||
|
@ -418,6 +419,7 @@ answer newbie questions, and generally made Django that much better:
|
|||
Christian Oudard <christian.oudard@gmail.com>
|
||||
oggie rob <oz.robharvey@gmail.com>
|
||||
oggy <ognjen.maric@gmail.com>
|
||||
Tomek Paczkowski <tomek@hauru.eu>
|
||||
Jens Page
|
||||
Jay Parlar <parlar@gmail.com>
|
||||
Carlos Eduardo de Paula <carlosedp@gmail.com>
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
from __future__ import absolute_import, unicode_literals
|
||||
|
||||
import hashlib
|
||||
from django.utils.encoding import force_bytes
|
||||
from django.utils.http import urlquote
|
||||
|
||||
TEMPLATE_FRAGMENT_KEY_TEMPLATE = 'template.cache.%s.%s'
|
||||
|
||||
|
||||
def make_template_fragment_key(fragment_name, vary_on=None):
|
||||
if vary_on is None:
|
||||
vary_on = ()
|
||||
key = ':'.join([urlquote(var) for var in vary_on])
|
||||
args = hashlib.md5(force_bytes(key))
|
||||
return TEMPLATE_FRAGMENT_KEY_TEMPLATE % (fragment_name, args.hexdigest())
|
|
@ -1,10 +1,8 @@
|
|||
from __future__ import unicode_literals
|
||||
|
||||
import hashlib
|
||||
from django.core.cache.utils import make_template_fragment_key
|
||||
from django.template import Library, Node, TemplateSyntaxError, VariableDoesNotExist
|
||||
from django.core.cache import cache
|
||||
from django.utils.encoding import force_bytes
|
||||
from django.utils.http import urlquote
|
||||
|
||||
register = Library()
|
||||
|
||||
|
@ -24,10 +22,8 @@ class CacheNode(Node):
|
|||
expire_time = int(expire_time)
|
||||
except (ValueError, TypeError):
|
||||
raise TemplateSyntaxError('"cache" tag got a non-integer timeout value: %r' % expire_time)
|
||||
# Build a key for this fragment and all vary-on's.
|
||||
key = ':'.join([urlquote(var.resolve(context)) for var in self.vary_on])
|
||||
args = hashlib.md5(force_bytes(key))
|
||||
cache_key = 'template.cache.%s.%s' % (self.fragment_name, args.hexdigest())
|
||||
vary_on = [var.resolve(context) for var in self.vary_on]
|
||||
cache_key = make_template_fragment_key(self.fragment_name, vary_on)
|
||||
value = cache.get(cache_key)
|
||||
if value is None:
|
||||
value = self.nodelist.render(context)
|
||||
|
|
|
@ -639,6 +639,23 @@ equivalent:
|
|||
This feature is useful in avoiding repetition in templates. You can set the
|
||||
timeout in a variable, in one place, and just reuse that value.
|
||||
|
||||
.. function:: django.core.cache.utils.make_template_fragment_key(fragment_name, vary_on=None)
|
||||
|
||||
If you want to obtain the cache key used for a cached fragment, you can use
|
||||
``make_template_fragment_key``. ``fragment_name`` is the same as second argument
|
||||
to the ``cache`` template tag; ``vary_on`` is a list of all additional arguments
|
||||
passed to the tag. This function can be useful for invalidating or overwriting
|
||||
a cached item, for example:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> from django.core.cache import cache
|
||||
>>> from django.core.cache.utils import make_template_fragment_key
|
||||
# cache key for {% cache 500 sidebar username %}
|
||||
>>> key = make_template_fragment_key('sidebar', [username])
|
||||
>>> cache.delete(key) # invalidates cached template fragment
|
||||
|
||||
|
||||
The low-level cache API
|
||||
=======================
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@ from django.core.cache import get_cache
|
|||
from django.core.cache.backends.base import (CacheKeyWarning,
|
||||
InvalidCacheBackendError)
|
||||
from django.db import router, transaction
|
||||
from django.core.cache.utils import make_template_fragment_key
|
||||
from django.http import (HttpResponse, HttpRequest, StreamingHttpResponse,
|
||||
QueryDict)
|
||||
from django.middleware.cache import (FetchFromCacheMiddleware,
|
||||
|
@ -1809,3 +1810,25 @@ class TestEtagWithAdmin(TestCase):
|
|||
response = self.client.get('/test_admin/admin/')
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertTrue(response.has_header('ETag'))
|
||||
|
||||
|
||||
class TestMakeTemplateFragmentKey(TestCase):
|
||||
def test_without_vary_on(self):
|
||||
key = make_template_fragment_key('a.fragment')
|
||||
self.assertEqual(key, 'template.cache.a.fragment.d41d8cd98f00b204e9800998ecf8427e')
|
||||
|
||||
def test_with_one_vary_on(self):
|
||||
key = make_template_fragment_key('foo', ['abc'])
|
||||
self.assertEqual(key,
|
||||
'template.cache.foo.900150983cd24fb0d6963f7d28e17f72')
|
||||
|
||||
def test_with_many_vary_on(self):
|
||||
key = make_template_fragment_key('bar', ['abc', 'def'])
|
||||
self.assertEqual(key,
|
||||
'template.cache.bar.4b35f12ab03cec09beec4c21b2d2fa88')
|
||||
|
||||
def test_proper_escaping(self):
|
||||
key = make_template_fragment_key('spam', ['abc:def%'])
|
||||
self.assertEqual(key,
|
||||
'template.cache.spam.f27688177baec990cdf3fbd9d9c3f469')
|
||||
|
||||
|
|
Loading…
Reference in New Issue