Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Fixed #20945 -- Allowed cache tag to use a specific cache.

  • Loading branch information...
commit 8688f03eef9cf5fd763ba35481ddcff933a60c30 1 parent 4ce5c11
@funkybob funkybob authored timgraham committed
View
34 django/templatetags/cache.py
@@ -1,17 +1,24 @@
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:
@@ -22,6 +29,17 @@ def render(self, context):
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)
@@ -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',))
@@ -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,
+ )
View
5 docs/releases/1.7.txt
@@ -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
^^^^^^^^
View
13 docs/topics/cache.txt
@@ -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
View
37 tests/template_tests/tests.py
@@ -478,6 +478,42 @@ def test_cache_regression_20130(self):
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."""
@@ -1736,7 +1772,6 @@ def get_template_tests(self):
# 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>"),
Please sign in to comment.
Something went wrong with that request. Please try again.