| 1 |
from django.template import Library, Node, TemplateSyntaxError, Variable, VariableDoesNotExist |
|---|
| 2 |
from django.template import resolve_variable |
|---|
| 3 |
from django.core.cache import cache |
|---|
| 4 |
from django.utils.encoding import force_unicode |
|---|
| 5 |
from django.utils.http import urlquote |
|---|
| 6 |
|
|---|
| 7 |
register = Library() |
|---|
| 8 |
|
|---|
| 9 |
class CacheNode(Node): |
|---|
| 10 |
def __init__(self, nodelist, expire_time_var, fragment_name, vary_on): |
|---|
| 11 |
self.nodelist = nodelist |
|---|
| 12 |
self.expire_time_var = Variable(expire_time_var) |
|---|
| 13 |
self.fragment_name = fragment_name |
|---|
| 14 |
self.vary_on = vary_on |
|---|
| 15 |
|
|---|
| 16 |
def render(self, context): |
|---|
| 17 |
try: |
|---|
| 18 |
expire_time = self.expire_time_var.resolve(context) |
|---|
| 19 |
except VariableDoesNotExist: |
|---|
| 20 |
raise TemplateSyntaxError('"cache" tag got an unknkown variable: %r' % self.expire_time_var.var) |
|---|
| 21 |
try: |
|---|
| 22 |
expire_time = int(expire_time) |
|---|
| 23 |
except (ValueError, TypeError): |
|---|
| 24 |
raise TemplateSyntaxError('"cache" tag got a non-integer timeout value: %r' % expire_time) |
|---|
| 25 |
# Build a unicode key for this fragment and all vary-on's. |
|---|
| 26 |
cache_key = u':'.join([self.fragment_name] + [urlquote(resolve_variable(var, context)) for var in self.vary_on]) |
|---|
| 27 |
value = cache.get(cache_key) |
|---|
| 28 |
if value is None: |
|---|
| 29 |
value = self.nodelist.render(context) |
|---|
| 30 |
cache.set(cache_key, value, expire_time) |
|---|
| 31 |
return value |
|---|
| 32 |
|
|---|
| 33 |
def do_cache(parser, token): |
|---|
| 34 |
""" |
|---|
| 35 |
This will cache the contents of a template fragment for a given amount |
|---|
| 36 |
of time. |
|---|
| 37 |
|
|---|
| 38 |
Usage:: |
|---|
| 39 |
|
|---|
| 40 |
{% load cache %} |
|---|
| 41 |
{% cache [expire_time] [fragment_name] %} |
|---|
| 42 |
.. some expensive processing .. |
|---|
| 43 |
{% endcache %} |
|---|
| 44 |
|
|---|
| 45 |
This tag also supports varying by a list of arguments:: |
|---|
| 46 |
|
|---|
| 47 |
{% load cache %} |
|---|
| 48 |
{% cache [expire_time] [fragment_name] [var1] [var2] .. %} |
|---|
| 49 |
.. some expensive processing .. |
|---|
| 50 |
{% endcache %} |
|---|
| 51 |
|
|---|
| 52 |
Each unique set of arguments will result in a unique cache entry. |
|---|
| 53 |
""" |
|---|
| 54 |
nodelist = parser.parse(('endcache',)) |
|---|
| 55 |
parser.delete_first_token() |
|---|
| 56 |
tokens = token.contents.split() |
|---|
| 57 |
if len(tokens) < 3: |
|---|
| 58 |
raise TemplateSyntaxError(u"'%r' tag requires at least 2 arguments." % tokens[0]) |
|---|
| 59 |
return CacheNode(nodelist, tokens[1], tokens[2], tokens[3:]) |
|---|
| 60 |
|
|---|
| 61 |
register.tag('cache', do_cache) |
|---|