Since Django's cache_page is rubbish with middleware, I had to write a new simple middleware that will allow you to opt-in pages to caching (like
@cache_page), however will work with various middlewares (e.g. sessions, languages), like the usually Django per-site cache.
This is the code, just put it in a file somewhere
from functools import wraps class DefaultDontCacheMiddleware(): """ A middleware that will mark every request as not to be cached. This allows one to use the Django (Update|FetchFrom)CacheMiddleware middlewares without having caching turned on for every view. This allows an opt-in cache, not opt-out """ def process_request(self, request): request._cache_update_cache = False def mark_for_caching(func): """ Decorator that enabled caching for this page. It's similar to ``cache_page`` decorator, but will work with middlewares that set headers (e.g. LocaleMiddleWare, SessionMiddleware, AuthenticationMiddleware etc.) """ @wraps(func) def newfunc(request, *args, **kwargs): request._cache_update_cache = True return func(request, *args, **kwargs) return newfunc
You have to load the
DefaultDontCacheMiddleware after the
django.middleware.cache.FetchFromCacheMiddleware, this is because the FetchFromCacheMiddleware will, if there is a cache miss, mark that request as something to cache in the UpdateCacheMiddleware. We must override it's behaviour, and tell it not to cache anything by default
For each view that you want cached, just put the
@mark_for_caching decorator on it, in the same way that you use the
I had to look through the Django caching code to try to figure out what was going on, and saw that the cache will only be updated if the
request has the
_cache_update_cache attritube True. This allows you to prevent caching. It is set to True by the
FetchFromCacheMiddleware if there is a cache miss, so that the results of the view function will be cached. After the
FetchFromCacheMiddleware is called, our
DefaultDontCacheMiddleware is called and it sets that to False, so that by the time it gets back up to the
UpdateCacheMiddleware, it's not cached.
However if the view goes through the
@mark_for_caching decorator, then that value is set to it's value of True, and the
UpdateCacheMiddleware will store the result, along with any of the
Vary headers or
Content-Language headers as apporpriate.