- Author:
- michiel_1981
- Posted:
- February 24, 2008
- Language:
- Python
- Version:
- .96
- Score:
- 2 (after 2 ratings)
cache_smart template tag is a drop in replacement for default cache tag by Django but with the added bonus to be more resistant against dog-pile/stampeding effect.
This snippet uses a extra cache entry to store a stale time so we don't have to pickle/unpickle to store this extra value. If this cache entry returns None, as in expired it will reset the stale timeout 30 seconds in the future so further calls will just return the old value while this request is regenerating the new value.
warning Don't use both cache template tags!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 | 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 SmartCacheNode(Node):
STALE_REFRESH = 1
STALE_CREATED = 2
def __init__(self, nodelist, expire_time, fragment_name, vary_on):
self.nodelist = nodelist
self.stale_time = expire_time
self.expire_time = expire_time + 300 # create a window to refresh
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])
cache_key_stale = cache_key + '.stale'
value = cache.get(cache_key)
stale = cache.get(cache_key_stale)
if stale is None:
cache.set(cache_key_stale, self.STALE_REFRESH, 30) # lock
value = None # force refresh
if value is None:
value = self.nodelist.render(context)
cache.set(cache_key, value, self.expire_time)
cache.set(cache_key_stale, self.STALE_CREATED, self.stale_time) # reset return value
def do_smart_cache(parser, token):
"""
This will cache the contents of a template fragment for a given amount
of time, but with the extra bonus of limiting the dog-pile/stampeding
effect.
You can easily replace the default template cache, just change the load
statement from ``{% load cache %}`` to ``{% load cache_smart %}``.
Usage::
{% load cache_smart %}
{% cache [expire_time] [fragment_name] %}
.. some expensive processing ..
{% endcache %}
This tag also supports varying by a list of arguments::
{% load cache_smart %}
{% 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 SmartCacheNode(nodelist, expire_time, tokens[2], tokens[3:])
register.tag('cache', do_smart_cache)
|
More like this
- Template tag - list punctuation for a list of items by shapiromatron 10 months, 2 weeks ago
- JSONRequestMiddleware adds a .json() method to your HttpRequests by cdcarter 10 months, 3 weeks ago
- Serializer factory with Django Rest Framework by julio 1 year, 5 months ago
- Image compression before saving the new model / work with JPG, PNG by Schleidens 1 year, 6 months ago
- Help text hyperlinks by sa2812 1 year, 6 months ago
Comments
Please login first before commenting.