Loading django/templatetags/cache.py +31 −3 Original line number Diff line number Diff line from __future__ import unicode_literals from django.core.cache import get_cache, InvalidCacheBackendError from django.core.cache.utils import make_template_fragment_key from django.template import Library, Node, TemplateSyntaxError, VariableDoesNotExist from django.core.cache import cache register = Library() try: default_cache = get_cache('template_fragments') except InvalidCacheBackendError: from django.core.cache import cache as default_cache class CacheNode(Node): def __init__(self, nodelist, expire_time_var, fragment_name, vary_on): def __init__(self, nodelist, expire_time_var, fragment_name, vary_on, cache_name): self.nodelist = nodelist self.expire_time_var = expire_time_var self.fragment_name = fragment_name self.vary_on = vary_on self.cache_name = cache_name def render(self, context): try: Loading @@ -22,6 +29,17 @@ class CacheNode(Node): expire_time = int(expire_time) except (ValueError, TypeError): raise TemplateSyntaxError('"cache" tag got a non-integer timeout value: %r' % expire_time) if self.cache_name: try: cache_name = self.cache_name.resolve(context) except VariableDoesNotExist: raise TemplateSyntaxError('"cache" tag got an unknown variable: %r' % self.cache_name.var) try: cache = get_cache(cache_name) except InvalidCacheBackendError: raise TemplateSyntaxError('Invalid cache name specified for cache tag: %r' % cache_name) else: cache = default_cache 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) Loading Loading @@ -50,6 +68,9 @@ def do_cache(parser, token): .. some expensive processing .. {% endcache %} Optionally the cache to use may be specified thus:: {% cache .... using="cachename" %} Each unique set of arguments will result in a unique cache entry. """ nodelist = parser.parse(('endcache',)) Loading @@ -57,7 +78,14 @@ def do_cache(parser, token): tokens = token.split_contents() if len(tokens) < 3: raise TemplateSyntaxError("'%r' tag requires at least 2 arguments." % tokens[0]) if len(tokens) > 3 and tokens[-1].startswith('using='): cache_name = parser.compile_filter(tokens[-1][len('using='):]) tokens = tokens[:-1] else: cache_name = None return CacheNode(nodelist, parser.compile_filter(tokens[1]), tokens[2], # fragment_name can't be a variable. [parser.compile_filter(t) for t in tokens[3:]]) [parser.compile_filter(t) for t in tokens[3:]], cache_name, ) docs/releases/1.7.txt +5 −0 Original line number Diff line number Diff line Loading @@ -396,6 +396,11 @@ Templates <naive_vs_aware_datetimes>` ``datetime`` instances performing the expected rendering. * The :ttag:`cache` tag will now try to use the cache called "template_fragments" if it exists and fall back to using the default cache otherwise. It also now accepts an optional ``using`` keyword argument to control which cache it uses. Requests ^^^^^^^^ Loading docs/topics/cache.txt +13 −0 Original line number Diff line number Diff line Loading @@ -652,6 +652,19 @@ 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. .. versionadded:: 1.7 By default, the cache tag will try to use the cache called "template_fragments". If no such cache exists, it will fall back to using the default cache. You may select an alternate cache backend to use with the ``using`` keyword argument, which must be the last argument to the tag. .. code-block:: html+django {% cache 300 local-thing ... using="localcache" %} It is considered an error to specify a cache name that is not configured. .. 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 Loading tests/template_tests/tests.py +36 −1 Original line number Diff line number Diff line Loading @@ -478,6 +478,42 @@ class TemplateRegressionTests(TestCase): cachenode = t.nodelist[1] self.assertEqual(cachenode.fragment_name, 'regression_20130') @override_settings(CACHES={ 'default': { 'BACKEND': 'django.core.cache.backends.locmem.LocMemCache', 'LOCATION': 'default', }, 'template_fragments': { 'BACKEND': 'django.core.cache.backends.locmem.LocMemCache', 'LOCATION': 'fragments', }, }) def test_cache_fragment_cache(self): """ When a cache called "template_fragments" is present, the cache tag will use it in preference to 'default' """ t1 = Template('{% load cache %}{% cache 1 fragment %}foo{% endcache %}') t2 = Template('{% load cache %}{% cache 1 fragment using="default" %}bar{% endcache %}') ctx = Context() o1 = t1.render(ctx) o2 = t2.render(ctx) self.assertEqual(o1, 'foo') self.assertNotEqual(o1, o2) def test_cache_missing_backend(self): """ When a cache that doesn't exist is specified, the cache tag will raise a TemplateSyntaxError '""" t = Template('{% load cache %}{% cache 1 backend using="unknown" %}bar{% endcache %}') ctx = Context() with self.assertRaises(TemplateSyntaxError): t.render(ctx) def test_ifchanged_render_once(self): """ Test for ticket #19890. The content of ifchanged template tag was rendered twice.""" Loading Loading @@ -1736,7 +1772,6 @@ class TemplateTests(TransRealMixin, TestCase): # Test whitespace in filter arguments 'cache18': ('{% load cache custom %}{% cache 2|noop:"x y" cache18 %}cache18{% endcache %}', {}, 'cache18'), ### AUTOESCAPE TAG ############################################## 'autoescape-tag01': ("{% autoescape off %}hello{% endautoescape %}", {}, "hello"), 'autoescape-tag02': ("{% autoescape off %}{{ first }}{% endautoescape %}", {"first": "<b>hello</b>"}, "<b>hello</b>"), Loading Loading
django/templatetags/cache.py +31 −3 Original line number Diff line number Diff line from __future__ import unicode_literals from django.core.cache import get_cache, InvalidCacheBackendError from django.core.cache.utils import make_template_fragment_key from django.template import Library, Node, TemplateSyntaxError, VariableDoesNotExist from django.core.cache import cache register = Library() try: default_cache = get_cache('template_fragments') except InvalidCacheBackendError: from django.core.cache import cache as default_cache class CacheNode(Node): def __init__(self, nodelist, expire_time_var, fragment_name, vary_on): def __init__(self, nodelist, expire_time_var, fragment_name, vary_on, cache_name): self.nodelist = nodelist self.expire_time_var = expire_time_var self.fragment_name = fragment_name self.vary_on = vary_on self.cache_name = cache_name def render(self, context): try: Loading @@ -22,6 +29,17 @@ class CacheNode(Node): expire_time = int(expire_time) except (ValueError, TypeError): raise TemplateSyntaxError('"cache" tag got a non-integer timeout value: %r' % expire_time) if self.cache_name: try: cache_name = self.cache_name.resolve(context) except VariableDoesNotExist: raise TemplateSyntaxError('"cache" tag got an unknown variable: %r' % self.cache_name.var) try: cache = get_cache(cache_name) except InvalidCacheBackendError: raise TemplateSyntaxError('Invalid cache name specified for cache tag: %r' % cache_name) else: cache = default_cache 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) Loading Loading @@ -50,6 +68,9 @@ def do_cache(parser, token): .. some expensive processing .. {% endcache %} Optionally the cache to use may be specified thus:: {% cache .... using="cachename" %} Each unique set of arguments will result in a unique cache entry. """ nodelist = parser.parse(('endcache',)) Loading @@ -57,7 +78,14 @@ def do_cache(parser, token): tokens = token.split_contents() if len(tokens) < 3: raise TemplateSyntaxError("'%r' tag requires at least 2 arguments." % tokens[0]) if len(tokens) > 3 and tokens[-1].startswith('using='): cache_name = parser.compile_filter(tokens[-1][len('using='):]) tokens = tokens[:-1] else: cache_name = None return CacheNode(nodelist, parser.compile_filter(tokens[1]), tokens[2], # fragment_name can't be a variable. [parser.compile_filter(t) for t in tokens[3:]]) [parser.compile_filter(t) for t in tokens[3:]], cache_name, )
docs/releases/1.7.txt +5 −0 Original line number Diff line number Diff line Loading @@ -396,6 +396,11 @@ Templates <naive_vs_aware_datetimes>` ``datetime`` instances performing the expected rendering. * The :ttag:`cache` tag will now try to use the cache called "template_fragments" if it exists and fall back to using the default cache otherwise. It also now accepts an optional ``using`` keyword argument to control which cache it uses. Requests ^^^^^^^^ Loading
docs/topics/cache.txt +13 −0 Original line number Diff line number Diff line Loading @@ -652,6 +652,19 @@ 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. .. versionadded:: 1.7 By default, the cache tag will try to use the cache called "template_fragments". If no such cache exists, it will fall back to using the default cache. You may select an alternate cache backend to use with the ``using`` keyword argument, which must be the last argument to the tag. .. code-block:: html+django {% cache 300 local-thing ... using="localcache" %} It is considered an error to specify a cache name that is not configured. .. 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 Loading
tests/template_tests/tests.py +36 −1 Original line number Diff line number Diff line Loading @@ -478,6 +478,42 @@ class TemplateRegressionTests(TestCase): cachenode = t.nodelist[1] self.assertEqual(cachenode.fragment_name, 'regression_20130') @override_settings(CACHES={ 'default': { 'BACKEND': 'django.core.cache.backends.locmem.LocMemCache', 'LOCATION': 'default', }, 'template_fragments': { 'BACKEND': 'django.core.cache.backends.locmem.LocMemCache', 'LOCATION': 'fragments', }, }) def test_cache_fragment_cache(self): """ When a cache called "template_fragments" is present, the cache tag will use it in preference to 'default' """ t1 = Template('{% load cache %}{% cache 1 fragment %}foo{% endcache %}') t2 = Template('{% load cache %}{% cache 1 fragment using="default" %}bar{% endcache %}') ctx = Context() o1 = t1.render(ctx) o2 = t2.render(ctx) self.assertEqual(o1, 'foo') self.assertNotEqual(o1, o2) def test_cache_missing_backend(self): """ When a cache that doesn't exist is specified, the cache tag will raise a TemplateSyntaxError '""" t = Template('{% load cache %}{% cache 1 backend using="unknown" %}bar{% endcache %}') ctx = Context() with self.assertRaises(TemplateSyntaxError): t.render(ctx) def test_ifchanged_render_once(self): """ Test for ticket #19890. The content of ifchanged template tag was rendered twice.""" Loading Loading @@ -1736,7 +1772,6 @@ class TemplateTests(TransRealMixin, TestCase): # Test whitespace in filter arguments 'cache18': ('{% load cache custom %}{% cache 2|noop:"x y" cache18 %}cache18{% endcache %}', {}, 'cache18'), ### AUTOESCAPE TAG ############################################## 'autoescape-tag01': ("{% autoescape off %}hello{% endautoescape %}", {}, "hello"), 'autoescape-tag02': ("{% autoescape off %}{{ first }}{% endautoescape %}", {"first": "<b>hello</b>"}, "<b>hello</b>"), Loading