Fixed #20945 -- Allowed cache tag to use a specific cache.
This commit is contained in:
parent
4ce5c119b5
commit
8688f03eef
|
@ -1,17 +1,24 @@
|
||||||
from __future__ import unicode_literals
|
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.core.cache.utils import make_template_fragment_key
|
||||||
from django.template import Library, Node, TemplateSyntaxError, VariableDoesNotExist
|
from django.template import Library, Node, TemplateSyntaxError, VariableDoesNotExist
|
||||||
from django.core.cache import cache
|
|
||||||
|
|
||||||
register = Library()
|
register = Library()
|
||||||
|
|
||||||
|
try:
|
||||||
|
default_cache = get_cache('template_fragments')
|
||||||
|
except InvalidCacheBackendError:
|
||||||
|
from django.core.cache import cache as default_cache
|
||||||
|
|
||||||
|
|
||||||
class CacheNode(Node):
|
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.nodelist = nodelist
|
||||||
self.expire_time_var = expire_time_var
|
self.expire_time_var = expire_time_var
|
||||||
self.fragment_name = fragment_name
|
self.fragment_name = fragment_name
|
||||||
self.vary_on = vary_on
|
self.vary_on = vary_on
|
||||||
|
self.cache_name = cache_name
|
||||||
|
|
||||||
def render(self, context):
|
def render(self, context):
|
||||||
try:
|
try:
|
||||||
|
@ -22,6 +29,17 @@ class CacheNode(Node):
|
||||||
expire_time = int(expire_time)
|
expire_time = int(expire_time)
|
||||||
except (ValueError, TypeError):
|
except (ValueError, TypeError):
|
||||||
raise TemplateSyntaxError('"cache" tag got a non-integer timeout value: %r' % expire_time)
|
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]
|
vary_on = [var.resolve(context) for var in self.vary_on]
|
||||||
cache_key = make_template_fragment_key(self.fragment_name, vary_on)
|
cache_key = make_template_fragment_key(self.fragment_name, vary_on)
|
||||||
value = cache.get(cache_key)
|
value = cache.get(cache_key)
|
||||||
|
@ -50,6 +68,9 @@ def do_cache(parser, token):
|
||||||
.. some expensive processing ..
|
.. some expensive processing ..
|
||||||
{% endcache %}
|
{% 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.
|
Each unique set of arguments will result in a unique cache entry.
|
||||||
"""
|
"""
|
||||||
nodelist = parser.parse(('endcache',))
|
nodelist = parser.parse(('endcache',))
|
||||||
|
@ -57,7 +78,14 @@ def do_cache(parser, token):
|
||||||
tokens = token.split_contents()
|
tokens = token.split_contents()
|
||||||
if len(tokens) < 3:
|
if len(tokens) < 3:
|
||||||
raise TemplateSyntaxError("'%r' tag requires at least 2 arguments." % tokens[0])
|
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,
|
return CacheNode(nodelist,
|
||||||
parser.compile_filter(tokens[1]),
|
parser.compile_filter(tokens[1]),
|
||||||
tokens[2], # fragment_name can't be a variable.
|
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,
|
||||||
|
)
|
||||||
|
|
|
@ -396,6 +396,11 @@ Templates
|
||||||
<naive_vs_aware_datetimes>` ``datetime`` instances performing the expected
|
<naive_vs_aware_datetimes>` ``datetime`` instances performing the expected
|
||||||
rendering.
|
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
|
Requests
|
||||||
^^^^^^^^
|
^^^^^^^^
|
||||||
|
|
||||||
|
|
|
@ -652,6 +652,19 @@ equivalent:
|
||||||
This feature is useful in avoiding repetition in templates. You can set the
|
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.
|
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)
|
.. 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
|
If you want to obtain the cache key used for a cached fragment, you can use
|
||||||
|
|
|
@ -478,6 +478,42 @@ class TemplateRegressionTests(TestCase):
|
||||||
cachenode = t.nodelist[1]
|
cachenode = t.nodelist[1]
|
||||||
self.assertEqual(cachenode.fragment_name, 'regression_20130')
|
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):
|
def test_ifchanged_render_once(self):
|
||||||
""" Test for ticket #19890. The content of ifchanged template tag was
|
""" Test for ticket #19890. The content of ifchanged template tag was
|
||||||
rendered twice."""
|
rendered twice."""
|
||||||
|
@ -1736,7 +1772,6 @@ class TemplateTests(TransRealMixin, TestCase):
|
||||||
# Test whitespace in filter arguments
|
# Test whitespace in filter arguments
|
||||||
'cache18': ('{% load cache custom %}{% cache 2|noop:"x y" cache18 %}cache18{% endcache %}', {}, 'cache18'),
|
'cache18': ('{% load cache custom %}{% cache 2|noop:"x y" cache18 %}cache18{% endcache %}', {}, 'cache18'),
|
||||||
|
|
||||||
|
|
||||||
### AUTOESCAPE TAG ##############################################
|
### AUTOESCAPE TAG ##############################################
|
||||||
'autoescape-tag01': ("{% autoescape off %}hello{% endautoescape %}", {}, "hello"),
|
'autoescape-tag01': ("{% autoescape off %}hello{% endautoescape %}", {}, "hello"),
|
||||||
'autoescape-tag02': ("{% autoescape off %}{{ first }}{% endautoescape %}", {"first": "<b>hello</b>"}, "<b>hello</b>"),
|
'autoescape-tag02': ("{% autoescape off %}{{ first }}{% endautoescape %}", {"first": "<b>hello</b>"}, "<b>hello</b>"),
|
||||||
|
|
Loading…
Reference in New Issue