Fixed #1065 -- Added a "cache" template tag. Thanks, Ian Maurer and, particularly, Nick Lane.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@6580 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
c64a6c98c4
commit
6fbf653aa5
|
@ -0,0 +1,57 @@
|
||||||
|
from django.template import Library, Node, TemplateSyntaxError
|
||||||
|
from django.template import resolve_variable
|
||||||
|
from django.core.cache import cache
|
||||||
|
from django.utils.encoding import force_unicode
|
||||||
|
|
||||||
|
register = Library()
|
||||||
|
|
||||||
|
class CacheNode(Node):
|
||||||
|
def __init__(self, nodelist, expire_time, fragment_name, vary_on):
|
||||||
|
self.nodelist = nodelist
|
||||||
|
self.expire_time = expire_time
|
||||||
|
self.fragment_name = fragment_name
|
||||||
|
self.vary_on = vary_on
|
||||||
|
|
||||||
|
def render(self, context):
|
||||||
|
# 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])
|
||||||
|
value = cache.get(cache_key)
|
||||||
|
if value is None:
|
||||||
|
value = self.nodelist.render(context)
|
||||||
|
cache.set(cache_key, value, self.expire_time)
|
||||||
|
return value
|
||||||
|
|
||||||
|
def do_cache(parser, token):
|
||||||
|
"""
|
||||||
|
This will cache the contents of a template fragment for a given amount
|
||||||
|
of time.
|
||||||
|
|
||||||
|
Usage::
|
||||||
|
|
||||||
|
{% load cache %}
|
||||||
|
{% cache [expire_time] [fragment_name] %}
|
||||||
|
.. some expensive processing ..
|
||||||
|
{% endcache %}
|
||||||
|
|
||||||
|
This tag also supports varying by a list of arguments::
|
||||||
|
|
||||||
|
{% load cache %}
|
||||||
|
{% cache [expire_time] [fragment_name] [var1] [var2] .. %}
|
||||||
|
.. some expensive processing ..
|
||||||
|
{% endcache %}
|
||||||
|
|
||||||
|
Each unique set of arguments will result in a unique cache entry.
|
||||||
|
"""
|
||||||
|
nodelist = parser.parse(('endcache',))
|
||||||
|
parser.delete_first_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:])
|
||||||
|
|
||||||
|
register.tag('cache', do_cache)
|
|
@ -288,6 +288,36 @@ Or, using Python 2.4's decorator syntax::
|
||||||
above example, the result of the ``slashdot_this()`` view will be cached for 15
|
above example, the result of the ``slashdot_this()`` view will be cached for 15
|
||||||
minutes.
|
minutes.
|
||||||
|
|
||||||
|
Template fragment caching
|
||||||
|
=========================
|
||||||
|
|
||||||
|
If you're after even more control, you can also cache template fragments using
|
||||||
|
the ``cache`` template tag. To give your template access to this tag, put ``{%
|
||||||
|
load cache %}`` near the top of your template.
|
||||||
|
|
||||||
|
The ``{% cache %}`` template tag caches the contents of the block for a given
|
||||||
|
amount of time. It takes at least two arguments: the cache timeout, in
|
||||||
|
seconds, and the name to give the cache fragment. For example::
|
||||||
|
|
||||||
|
{% load cache %}
|
||||||
|
{% cache 500 sidebar %}
|
||||||
|
.. sidebar ..
|
||||||
|
{% endcache %}
|
||||||
|
|
||||||
|
Sometimes you might want to cache multiple copies of a fragment depending on
|
||||||
|
some dynamic data that appears inside the fragment. For example you may want a
|
||||||
|
separate cached copy of the sidebar used in the previous example for every user
|
||||||
|
of your site. This can be easily achieved by passing additional arguments to
|
||||||
|
the ``{% cache %}`` template tag to uniquely identify the cache fragment::
|
||||||
|
|
||||||
|
{% load cache %}
|
||||||
|
{% cache 500 sidebar request.user.username %}
|
||||||
|
.. sidebar for logged in user ..
|
||||||
|
{% endcache %}
|
||||||
|
|
||||||
|
If you need more than one argument to identify the fragment that's fine, simply
|
||||||
|
pass as many arguments to ``{% cache %}`` as you need!
|
||||||
|
|
||||||
The low-level cache API
|
The low-level cache API
|
||||||
=======================
|
=======================
|
||||||
|
|
||||||
|
|
|
@ -805,6 +805,20 @@ class Templates(unittest.TestCase):
|
||||||
'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 ######################################################
|
||||||
|
'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'),
|
||||||
|
|
||||||
|
# Raise exception if we dont 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),
|
||||||
}
|
}
|
||||||
|
|
||||||
# Register our custom template loader.
|
# Register our custom template loader.
|
||||||
|
|
Loading…
Reference in New Issue