diff --git a/django/templatetags/cache.py b/django/templatetags/cache.py index 4436b15d6e..07bd590fba 100644 --- a/django/templatetags/cache.py +++ b/django/templatetags/cache.py @@ -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.core.cache import cache from django.utils.encoding import force_unicode @@ -6,20 +6,27 @@ from django.utils.encoding import force_unicode register = Library() 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.expire_time = expire_time + self.expire_time_var = Variable(expire_time_var) self.fragment_name = fragment_name self.vary_on = vary_on 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. - cache_key = u':'.join([self.fragment_name] + \ - [force_unicode(resolve_variable(var, context)) for var in self.vary_on]) + cache_key = u':'.join([self.fragment_name] + [force_unicode(resolve_variable(var, context)) for var in self.vary_on]) value = cache.get(cache_key) if value is None: value = self.nodelist.render(context) - cache.set(cache_key, value, self.expire_time) + cache.set(cache_key, value, expire_time) return value def do_cache(parser, token): @@ -48,10 +55,6 @@ def do_cache(parser, token): tokens = token.contents.split() if len(tokens) < 3: raise TemplateSyntaxError(u"'%r' tag requires at least 2 arguments." % tokens[0]) - try: - 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:]) + return CacheNode(nodelist, tokens[1], tokens[2], tokens[3:]) register.tag('cache', do_cache) diff --git a/docs/cache.txt b/docs/cache.txt index e7e1cdd791..3318b2ad4a 100644 --- a/docs/cache.txt +++ b/docs/cache.txt @@ -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. 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 ======================= diff --git a/tests/regressiontests/templates/tests.py b/tests/regressiontests/templates/tests.py index a90392938d..186b8aacb5 100644 --- a/tests/regressiontests/templates/tests.py +++ b/tests/regressiontests/templates/tests.py @@ -863,40 +863,46 @@ class Templates(unittest.TestCase): ### NOW TAG ######################################################## # 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 - 'now02' : ('{% now "j "n" Y"%}', {}, template.TemplateSyntaxError), - # '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)) + 'now02': ('{% now "j "n" Y"%}', {}, template.TemplateSyntaxError), + # '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)) ### URL TAG ######################################################## # Successes - '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/'), - 'url03' : ('{% url regressiontests.templates.views.index %}', {}, '/url_tag/'), - 'url04' : ('{% url named.client client.id %}', {'client': {'id': 1}}, '/url_tag/named-client/1/'), - 'url05' : (u'{% url метка_оператора v %}', {'v': u'Ω'}, - '/url_tag/%D0%AE%D0%BD%D0%B8%D0%BA%D0%BE%D0%B4/%CE%A9/'), + '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/'), + 'url03': ('{% url regressiontests.templates.views.index %}', {}, '/url_tag/'), + 'url04': ('{% url named.client client.id %}', {'client': {'id': 1}}, '/url_tag/named-client/1/'), + 'url05': (u'{% url метка_оператора v %}', {'v': u'Ω'}, '/url_tag/%D0%AE%D0%BD%D0%B8%D0%BA%D0%BE%D0%B4/%CE%A9/'), # Failures - 'url-fail01' : ('{% url %}', {}, template.TemplateSyntaxError), - 'url-fail02' : ('{% url no_such_view %}', {}, ''), - 'url-fail03' : ('{% url regressiontests.templates.views.client no_such_param="value" %}', {}, ''), + 'url-fail01': ('{% url %}', {}, template.TemplateSyntaxError), + 'url-fail02': ('{% url no_such_view %}', {}, ''), + 'url-fail03': ('{% url regressiontests.templates.views.client no_such_param="value" %}', {}, ''), ### CACHE TAG ###################################################### - 'cache01' : ('{% load cache %}{% cache -1 test %}cache01{% endcache %}', {}, 'cache01'), - 'cache02' : ('{% load cache %}{% cache -1 test %}cache02{% endcache %}', {}, 'cache02'), - 'cache03' : ('{% load cache %}{% cache 2 test %}cache03{% endcache %}', {}, 'cache03'), - 'cache04' : ('{% load cache %}{% cache 2 test %}cache04{% endcache %}', {}, 'cache03'), - 'cache05' : ('{% load cache %}{% cache 2 test foo %}cache05{% endcache %}', {'foo': 1}, 'cache05'), - 'cache06' : ('{% load cache %}{% cache 2 test foo %}cache06{% endcache %}', {'foo': 2}, 'cache06'), - 'cache07' : ('{% load cache %}{% cache 2 test foo %}cache06{% endcache %}', {'foo': 1}, 'cache05'), + 'cache01': ('{% load cache %}{% cache -1 test %}cache01{% endcache %}', {}, 'cache01'), + 'cache02': ('{% load cache %}{% cache -1 test %}cache02{% endcache %}', {}, 'cache02'), + 'cache03': ('{% load cache %}{% cache 2 test %}cache03{% endcache %}', {}, 'cache03'), + 'cache04': ('{% load cache %}{% cache 2 test %}cache04{% endcache %}', {}, 'cache03'), + 'cache05': ('{% load cache %}{% cache 2 test foo %}cache05{% endcache %}', {'foo': 1}, 'cache05'), + 'cache06': ('{% load cache %}{% cache 2 test foo %}cache06{% endcache %}', {'foo': 2}, 'cache06'), + '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. - 'cache08' : ('{% load cache %}{% cache %}{% endcache %}', {}, template.TemplateSyntaxError), - 'cache09' : ('{% load cache %}{% cache 1 %}{% endcache %}', {}, template.TemplateSyntaxError), - 'cache10' : ('{% load cache %}{% cache foo bar %}{% endcache %}', {}, template.TemplateSyntaxError), + 'cache11': ('{% load cache %}{% cache %}{% endcache %}', {}, template.TemplateSyntaxError), + 'cache12': ('{% load cache %}{% cache 1 %}{% 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-tag01': ("{% autoescape off %}hello{% endautoescape %}", {}, "hello"),