Commit 74f0408f authored by Adrian Holovaty's avatar Adrian Holovaty
Browse files

Fixed #6201 -- Improved the {% cache %} template tag to allow the timeout to...

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
parent 5ee4a099
Loading
Loading
Loading
Loading
+14 −11
Original line number Diff line number Diff line
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)
+11 −0
Original line number Diff line number Diff line
@@ -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
=======================

+29 −23
Original line number Diff line number Diff line
@@ -876,8 +876,7 @@ class Templates(unittest.TestCase):
            '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/'),
            '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),
@@ -891,12 +890,19 @@ class Templates(unittest.TestCase):
            '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'),
            '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"),