Fixed #6201 -- Improved the {% cache %} template tag to allow the timeout to be a template variable. Inspired by the patch by zz and edrik
git-svn-id: http://code.djangoproject.com/svn/django/trunk@7754 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
5ee4a099f1
commit
74f0408fa2
|
@ -1,4 +1,4 @@
|
||||||
from django.template import Library, Node, TemplateSyntaxError
|
from django.template import Library, Node, TemplateSyntaxError, Variable, VariableDoesNotExist
|
||||||
from django.template import resolve_variable
|
from django.template import resolve_variable
|
||||||
from django.core.cache import cache
|
from django.core.cache import cache
|
||||||
from django.utils.encoding import force_unicode
|
from django.utils.encoding import force_unicode
|
||||||
|
@ -6,20 +6,27 @@ from django.utils.encoding import force_unicode
|
||||||
register = Library()
|
register = Library()
|
||||||
|
|
||||||
class CacheNode(Node):
|
class CacheNode(Node):
|
||||||
def __init__(self, nodelist, expire_time, fragment_name, vary_on):
|
def __init__(self, nodelist, expire_time_var, fragment_name, vary_on):
|
||||||
self.nodelist = nodelist
|
self.nodelist = nodelist
|
||||||
self.expire_time = expire_time
|
self.expire_time_var = Variable(expire_time_var)
|
||||||
self.fragment_name = fragment_name
|
self.fragment_name = fragment_name
|
||||||
self.vary_on = vary_on
|
self.vary_on = vary_on
|
||||||
|
|
||||||
def render(self, context):
|
def render(self, context):
|
||||||
|
try:
|
||||||
|
expire_time = self.expire_time_var.resolve(context)
|
||||||
|
except VariableDoesNotExist:
|
||||||
|
raise TemplateSyntaxError('"cache" tag got an unknkown variable: %r' % self.expire_time_var.var)
|
||||||
|
try:
|
||||||
|
expire_time = int(expire_time)
|
||||||
|
except (ValueError, TypeError):
|
||||||
|
raise TemplateSyntaxError('"cache" tag got a non-integer timeout value: %r' % expire_time)
|
||||||
# Build a unicode key for this fragment and all vary-on's.
|
# Build a unicode key for this fragment and all vary-on's.
|
||||||
cache_key = u':'.join([self.fragment_name] + \
|
cache_key = u':'.join([self.fragment_name] + [force_unicode(resolve_variable(var, context)) for var in self.vary_on])
|
||||||
[force_unicode(resolve_variable(var, context)) for var in self.vary_on])
|
|
||||||
value = cache.get(cache_key)
|
value = cache.get(cache_key)
|
||||||
if value is None:
|
if value is None:
|
||||||
value = self.nodelist.render(context)
|
value = self.nodelist.render(context)
|
||||||
cache.set(cache_key, value, self.expire_time)
|
cache.set(cache_key, value, expire_time)
|
||||||
return value
|
return value
|
||||||
|
|
||||||
def do_cache(parser, token):
|
def do_cache(parser, token):
|
||||||
|
@ -48,10 +55,6 @@ def do_cache(parser, token):
|
||||||
tokens = token.contents.split()
|
tokens = token.contents.split()
|
||||||
if len(tokens) < 3:
|
if len(tokens) < 3:
|
||||||
raise TemplateSyntaxError(u"'%r' tag requires at least 2 arguments." % tokens[0])
|
raise TemplateSyntaxError(u"'%r' tag requires at least 2 arguments." % tokens[0])
|
||||||
try:
|
return CacheNode(nodelist, tokens[1], tokens[2], tokens[3:])
|
||||||
expire_time = int(tokens[1])
|
|
||||||
except ValueError:
|
|
||||||
raise TemplateSyntaxError(u"First argument to '%r' must be an integer (got '%s')." % (tokens[0], tokens[1]))
|
|
||||||
return CacheNode(nodelist, expire_time, tokens[2], tokens[3:])
|
|
||||||
|
|
||||||
register.tag('cache', do_cache)
|
register.tag('cache', do_cache)
|
||||||
|
|
|
@ -336,6 +336,17 @@ template tag to uniquely identify the cache fragment::
|
||||||
It's perfectly fine to specify more than one argument to identify the fragment.
|
It's perfectly fine to specify more than one argument to identify the fragment.
|
||||||
Simply pass as many arguments to ``{% cache %}`` as you need.
|
Simply pass as many arguments to ``{% cache %}`` as you need.
|
||||||
|
|
||||||
|
The cache timeout can be a template variable, as long as the template variable
|
||||||
|
resolves to an integer value. For example, if the template variable
|
||||||
|
``my_timeout`` is set to the value ``600``, then the following two examples are
|
||||||
|
equivalent::
|
||||||
|
|
||||||
|
{% cache 600 sidebar %} ... {% endcache %}
|
||||||
|
{% cache my_timeout sidebar %} ... {% endcache %}
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
The low-level cache API
|
The low-level cache API
|
||||||
=======================
|
=======================
|
||||||
|
|
||||||
|
|
|
@ -863,40 +863,46 @@ class Templates(unittest.TestCase):
|
||||||
|
|
||||||
### NOW TAG ########################################################
|
### NOW TAG ########################################################
|
||||||
# Simple case
|
# Simple case
|
||||||
'now01' : ('{% now "j n Y"%}', {}, str(datetime.now().day) + ' ' + str(datetime.now().month) + ' ' + str(datetime.now().year)),
|
'now01': ('{% now "j n Y"%}', {}, str(datetime.now().day) + ' ' + str(datetime.now().month) + ' ' + str(datetime.now().year)),
|
||||||
|
|
||||||
# Check parsing of escaped and special characters
|
# Check parsing of escaped and special characters
|
||||||
'now02' : ('{% now "j "n" Y"%}', {}, template.TemplateSyntaxError),
|
'now02': ('{% now "j "n" Y"%}', {}, template.TemplateSyntaxError),
|
||||||
# 'now03' : ('{% now "j \"n\" Y"%}', {}, str(datetime.now().day) + '"' + str(datetime.now().month) + '"' + str(datetime.now().year)),
|
# 'now03': ('{% now "j \"n\" Y"%}', {}, str(datetime.now().day) + '"' + str(datetime.now().month) + '"' + str(datetime.now().year)),
|
||||||
# 'now04' : ('{% now "j \nn\n Y"%}', {}, str(datetime.now().day) + '\n' + str(datetime.now().month) + '\n' + str(datetime.now().year))
|
# 'now04': ('{% now "j \nn\n Y"%}', {}, str(datetime.now().day) + '\n' + str(datetime.now().month) + '\n' + str(datetime.now().year))
|
||||||
|
|
||||||
### URL TAG ########################################################
|
### URL TAG ########################################################
|
||||||
# Successes
|
# Successes
|
||||||
'url01' : ('{% url regressiontests.templates.views.client client.id %}', {'client': {'id': 1}}, '/url_tag/client/1/'),
|
'url01': ('{% url regressiontests.templates.views.client client.id %}', {'client': {'id': 1}}, '/url_tag/client/1/'),
|
||||||
'url02' : ('{% url regressiontests.templates.views.client_action client.id, action="update" %}', {'client': {'id': 1}}, '/url_tag/client/1/update/'),
|
'url02': ('{% url regressiontests.templates.views.client_action client.id, action="update" %}', {'client': {'id': 1}}, '/url_tag/client/1/update/'),
|
||||||
'url03' : ('{% url regressiontests.templates.views.index %}', {}, '/url_tag/'),
|
'url03': ('{% url regressiontests.templates.views.index %}', {}, '/url_tag/'),
|
||||||
'url04' : ('{% url named.client client.id %}', {'client': {'id': 1}}, '/url_tag/named-client/1/'),
|
'url04': ('{% url named.client client.id %}', {'client': {'id': 1}}, '/url_tag/named-client/1/'),
|
||||||
'url05' : (u'{% url метка_оператора v %}', {'v': u'Ω'},
|
'url05': (u'{% url метка_оператора v %}', {'v': u'Ω'}, '/url_tag/%D0%AE%D0%BD%D0%B8%D0%BA%D0%BE%D0%B4/%CE%A9/'),
|
||||||
'/url_tag/%D0%AE%D0%BD%D0%B8%D0%BA%D0%BE%D0%B4/%CE%A9/'),
|
|
||||||
|
|
||||||
# Failures
|
# Failures
|
||||||
'url-fail01' : ('{% url %}', {}, template.TemplateSyntaxError),
|
'url-fail01': ('{% url %}', {}, template.TemplateSyntaxError),
|
||||||
'url-fail02' : ('{% url no_such_view %}', {}, ''),
|
'url-fail02': ('{% url no_such_view %}', {}, ''),
|
||||||
'url-fail03' : ('{% url regressiontests.templates.views.client no_such_param="value" %}', {}, ''),
|
'url-fail03': ('{% url regressiontests.templates.views.client no_such_param="value" %}', {}, ''),
|
||||||
|
|
||||||
### CACHE TAG ######################################################
|
### CACHE TAG ######################################################
|
||||||
'cache01' : ('{% load cache %}{% cache -1 test %}cache01{% endcache %}', {}, 'cache01'),
|
'cache01': ('{% load cache %}{% cache -1 test %}cache01{% endcache %}', {}, 'cache01'),
|
||||||
'cache02' : ('{% load cache %}{% cache -1 test %}cache02{% endcache %}', {}, 'cache02'),
|
'cache02': ('{% load cache %}{% cache -1 test %}cache02{% endcache %}', {}, 'cache02'),
|
||||||
'cache03' : ('{% load cache %}{% cache 2 test %}cache03{% endcache %}', {}, 'cache03'),
|
'cache03': ('{% load cache %}{% cache 2 test %}cache03{% endcache %}', {}, 'cache03'),
|
||||||
'cache04' : ('{% load cache %}{% cache 2 test %}cache04{% endcache %}', {}, 'cache03'),
|
'cache04': ('{% load cache %}{% cache 2 test %}cache04{% endcache %}', {}, 'cache03'),
|
||||||
'cache05' : ('{% load cache %}{% cache 2 test foo %}cache05{% endcache %}', {'foo': 1}, 'cache05'),
|
'cache05': ('{% load cache %}{% cache 2 test foo %}cache05{% endcache %}', {'foo': 1}, 'cache05'),
|
||||||
'cache06' : ('{% load cache %}{% cache 2 test foo %}cache06{% endcache %}', {'foo': 2}, 'cache06'),
|
'cache06': ('{% load cache %}{% cache 2 test foo %}cache06{% endcache %}', {'foo': 2}, 'cache06'),
|
||||||
'cache07' : ('{% load cache %}{% cache 2 test foo %}cache06{% endcache %}', {'foo': 1}, 'cache05'),
|
'cache07': ('{% load cache %}{% cache 2 test foo %}cache07{% endcache %}', {'foo': 1}, 'cache05'),
|
||||||
|
|
||||||
|
# Allow first argument to be a variable.
|
||||||
|
'cache08': ('{% load cache %}{% cache time test foo %}cache08{% endcache %}', {'foo': 2, 'time': 2}, 'cache06'),
|
||||||
|
'cache09': ('{% load cache %}{% cache time test foo %}cache09{% endcache %}', {'foo': 3, 'time': -1}, 'cache09'),
|
||||||
|
'cache10': ('{% load cache %}{% cache time test foo %}cache10{% endcache %}', {'foo': 3, 'time': -1}, 'cache10'),
|
||||||
|
|
||||||
# Raise exception if we don't have at least 2 args, first one integer.
|
# Raise exception if we don't have at least 2 args, first one integer.
|
||||||
'cache08' : ('{% load cache %}{% cache %}{% endcache %}', {}, template.TemplateSyntaxError),
|
'cache11': ('{% load cache %}{% cache %}{% endcache %}', {}, template.TemplateSyntaxError),
|
||||||
'cache09' : ('{% load cache %}{% cache 1 %}{% endcache %}', {}, template.TemplateSyntaxError),
|
'cache12': ('{% load cache %}{% cache 1 %}{% endcache %}', {}, template.TemplateSyntaxError),
|
||||||
'cache10' : ('{% load cache %}{% cache foo bar %}{% endcache %}', {}, template.TemplateSyntaxError),
|
'cache13': ('{% load cache %}{% cache foo bar %}{% endcache %}', {}, template.TemplateSyntaxError),
|
||||||
|
'cache14': ('{% load cache %}{% cache foo bar %}{% endcache %}', {'foo': 'fail'}, template.TemplateSyntaxError),
|
||||||
|
'cache15': ('{% load cache %}{% cache foo bar %}{% endcache %}', {'foo': []}, template.TemplateSyntaxError),
|
||||||
|
|
||||||
### AUTOESCAPE TAG ##############################################
|
### AUTOESCAPE TAG ##############################################
|
||||||
'autoescape-tag01': ("{% autoescape off %}hello{% endautoescape %}", {}, "hello"),
|
'autoescape-tag01': ("{% autoescape off %}hello{% endautoescape %}", {}, "hello"),
|
||||||
|
|
Loading…
Reference in New Issue