This cache_page decorator can be used in replacement to Django's django.views.decorators.cache.cache_page.
It resolves two problems:
- invalidation (its cache key is not dependent of header nor request, then you can use model signals (or method 'put' in Google App Engine) to invalidate a URL or a list of them)
- easier to scale (can be used at once memcached server by many differente servers)
Feel free to show me where it can have problems or limitations.
Updated and improved a lot
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 | from django.core.cache import cache
from django.template.defaultfilters import slugify
from django.http import HttpResponse
from django.conf import settings
CACHE_KEY_PREFIX = settings.CACHE_MIDDLEWARE_KEY_PREFIX + 'cache-page:'
def invalidate_cache(url, html5=None):
"""Does cache invalidation for a given URL"""
cache.set(make_cache_key(url, html5), None)
def invalidate_all_cached_pages():
"""Invalidates all cached pages at once."""
keys = [key for key in cache._cache.keys() if key.startswith(CACHE_KEY_PREFIX)]
cache.set_many(dict([(key, None) for key in keys]))
def make_cache_key(url, html5=None):
key = CACHE_KEY_PREFIX + slugify(url)
if html5 == True:
key = '.'.join([key, 'html5'])
elif html5 == False:
key = '.'.join([key, 'html4'])
return key
def cache_page(arg=None): # 1 day as default
"""This decorator works in replacement to Django's decorator with same name, but
it doesn't use Django's middleware system to make cache key, so, it uses its own
logic to do it and make possible invalidate cache.
This decorator shouldn't be used to views with user-based data."""
default_exp = 60 * 30 # 30 minutes
def _wrapper(func):
def _inner(request, *args, **kwargs):
key = make_cache_key(request.get_full_path(), getattr(request, 'supports_html5', None))
content = cache.get(key, None)
if not content:
resp = func(request, *args, **kwargs)
content = resp.content
# Only stores in cache if is a regular HttpResponse returning text/html
if resp.__class__.__name__ == 'HttpResponse' and\
getattr(resp, 'mimetype', 'text/html') == 'text/html':
cache.set(key, content, expiration)
else:
return resp
return HttpResponse(content)
return _inner
if callable(arg):
expiration = default_exp
return _wrapper(arg)
else:
expiration = arg or default_exp
return _wrapper
|
More like this
- Template tag - list punctuation for a list of items by shapiromatron 11 months ago
- JSONRequestMiddleware adds a .json() method to your HttpRequests by cdcarter 11 months, 1 week 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, 7 months ago
Comments
Please login first before commenting.