Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

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
  • Loading branch information...
commit 6fbf653aa5aa15867e03a5c60bda599d5c99123c 1 parent c64a6c9
Malcolm Tredinnick authored
57  django/templatetags/cache.py
... ...
@@ -0,0 +1,57 @@
  1
+from django.template import Library, Node, TemplateSyntaxError
  2
+from django.template import resolve_variable
  3
+from django.core.cache import cache
  4
+from django.utils.encoding import force_unicode
  5
+
  6
+register = Library()
  7
+
  8
+class CacheNode(Node):
  9
+    def __init__(self, nodelist, expire_time, fragment_name, vary_on):
  10
+        self.nodelist = nodelist
  11
+        self.expire_time = expire_time
  12
+        self.fragment_name = fragment_name
  13
+        self.vary_on = vary_on
  14
+
  15
+    def render(self, context):
  16
+        # Build a unicode key for this fragment and all vary-on's.
  17
+        cache_key = u':'.join([self.fragment_name] + \
  18
+            [force_unicode(resolve_variable(var, context)) for var in self.vary_on])
  19
+        value = cache.get(cache_key)
  20
+        if value is None:
  21
+            value = self.nodelist.render(context)
  22
+            cache.set(cache_key, value, self.expire_time)
  23
+        return value
  24
+
  25
+def do_cache(parser, token):
  26
+    """
  27
+    This will cache the contents of a template fragment for a given amount
  28
+    of time.
  29
+
  30
+    Usage::
  31
+
  32
+        {% load cache %}
  33
+        {% cache [expire_time] [fragment_name] %}
  34
+            .. some expensive processing ..
  35
+        {% endcache %}
  36
+
  37
+    This tag also supports varying by a list of arguments::
  38
+
  39
+        {% load cache %}
  40
+        {% cache [expire_time] [fragment_name] [var1] [var2] .. %}
  41
+            .. some expensive processing ..
  42
+        {% endcache %}
  43
+
  44
+    Each unique set of arguments will result in a unique cache entry.
  45
+    """
  46
+    nodelist = parser.parse(('endcache',))
  47
+    parser.delete_first_token()
  48
+    tokens = token.contents.split()
  49
+    if len(tokens) < 3:
  50
+        raise TemplateSyntaxError(u"'%r' tag requires at least 2 arguments." % tokens[0])
  51
+    try:
  52
+        expire_time = int(tokens[1])
  53
+    except ValueError:
  54
+        raise TemplateSyntaxError(u"First argument to '%r' must be an integer (got '%s')." % (tokens[0], tokens[1]))
  55
+    return CacheNode(nodelist, expire_time, tokens[2], tokens[3:])
  56
+
  57
+register.tag('cache', do_cache)
30  docs/cache.txt
@@ -288,6 +288,36 @@ Or, using Python 2.4's decorator syntax::
288 288
 above example, the result of the ``slashdot_this()`` view will be cached for 15
289 289
 minutes.
290 290
 
  291
+Template fragment caching
  292
+=========================
  293
+
  294
+If you're after even more control, you can also cache template fragments using
  295
+the ``cache`` template tag. To give your template access to this tag, put ``{%
  296
+load cache %}`` near the top of your template.
  297
+
  298
+The ``{% cache %}`` template tag caches the contents of the block for a given
  299
+amount of time. It takes at least two arguments: the cache timeout, in
  300
+seconds, and the name to give the cache fragment. For example::
  301
+
  302
+    {% load cache %}
  303
+    {% cache 500 sidebar %}
  304
+        .. sidebar ..
  305
+    {% endcache %}
  306
+
  307
+Sometimes you might want to cache multiple copies of a fragment depending on
  308
+some dynamic data that appears inside the fragment. For example you may want a
  309
+separate cached copy of the sidebar used in the previous example for every user
  310
+of your site. This can be easily achieved by passing additional arguments to
  311
+the ``{% cache %}`` template tag to uniquely identify the cache fragment::
  312
+
  313
+    {% load cache %}
  314
+    {% cache 500 sidebar request.user.username %}
  315
+        .. sidebar for logged in user ..
  316
+    {% endcache %}
  317
+
  318
+If you need more than one argument to identify the fragment that's fine, simply
  319
+pass as many arguments to ``{% cache %}`` as you need!
  320
+
291 321
 The low-level cache API
292 322
 =======================
293 323
 
14  tests/regressiontests/templates/tests.py
@@ -805,6 +805,20 @@ def test_templates(self):
805 805
             'url-fail01' : ('{% url %}', {}, template.TemplateSyntaxError),
806 806
             'url-fail02' : ('{% url no_such_view %}', {}, ''),
807 807
             'url-fail03' : ('{% url regressiontests.templates.views.client no_such_param="value" %}', {}, ''),
  808
+
  809
+            ### CACHE TAG ######################################################
  810
+            'cache01' : ('{% load cache %}{% cache -1 test %}cache01{% endcache %}', {}, 'cache01'),
  811
+            'cache02' : ('{% load cache %}{% cache -1 test %}cache02{% endcache %}', {}, 'cache02'),
  812
+            'cache03' : ('{% load cache %}{% cache 2 test %}cache03{% endcache %}', {}, 'cache03'),
  813
+            'cache04' : ('{% load cache %}{% cache 2 test %}cache04{% endcache %}', {}, 'cache03'),
  814
+            'cache05' : ('{% load cache %}{% cache 2 test foo %}cache05{% endcache %}', {'foo': 1}, 'cache05'),
  815
+            'cache06' : ('{% load cache %}{% cache 2 test foo %}cache06{% endcache %}', {'foo': 2}, 'cache06'),
  816
+            'cache07' : ('{% load cache %}{% cache 2 test foo %}cache06{% endcache %}', {'foo': 1}, 'cache05'),
  817
+
  818
+            # Raise exception if we dont have at least 2 args, first one integer.
  819
+            'cache08' : ('{% load cache %}{% cache %}{% endcache %}', {}, template.TemplateSyntaxError),
  820
+            'cache09' : ('{% load cache %}{% cache 1 %}{% endcache %}', {}, template.TemplateSyntaxError),
  821
+            'cache10' : ('{% load cache %}{% cache foo bar %}{% endcache %}', {}, template.TemplateSyntaxError),
808 822
         }
809 823
 
810 824
         # Register our custom template loader.

0 notes on commit 6fbf653

Please sign in to comment.
Something went wrong with that request. Please try again.