Using django's site-wide cache middleware is pretty straight forward and acts as expected on a wagtail site. But what about per-view caching?
As it turns out, using django's per-view caching is quite easy to implement on wagtail Page sub-classes. Out of the box you can just do:
from django.views.decorators.cache import cache_page from django.utils.decorators import method_decorator from wagtail.wagtailcore.models import Page @method_decorator(cache_page(300), name="serve") class MyPage(Page): # my class code here
You can also add optional keyword arguments for 'key_prefix' and 'cache' to the 'cache_page' decorator. This gives quite a lot of flexibility and control over where a view is cached and what it's cache_key will be based on.
But what if you wanted to have a dynamic 'key_prefix', say based on the MyPage primary key? Well then you would need access to the instance of MyPage (self) and you can't do this with 'method_decorator'.
I wrote a decorator (based on 'method_decorator') that works for wagtail's Page and its sub-classes:
from django.views.decorators.cache import cache_page def wagtail_cache_page(timeout, cache="", key_prefix="", append_key_prefix_with_pk=False): def inner(obj): """ obj can be a class or method. Must be either a wagtail Page subclass or the 'serve' method of a wagtail Page subclass """ is_class = isinstance(obj, type) if is_class: if hasattr(obj, 'serve'): serve = getattr(obj, 'serve') if not callable(serve): raise TypeError("Cannot decorate 'serve' as it isn't a callable ") else: raise ValueError("The Class must have a 'serve' method. ") else: serve = obj def wrapper(self, request, *args, **kwargs): suffix = str(self.pk) if append_key_prefix_with_pk else '' @cache_page(timeout, cache=cache, key_prefix=key_prefix + suffix) def _cache_page_hack(request, self, *args, **kwargs): return serve(self, request, *args, **kwargs) return _cache_page_hack(request, self, *args, **kwargs) if is_class: setattr(obj, 'serve', wrapper) return obj return wrapper return inner
This will append the instance primary key to the 'key_prefix', which can be quite handy when trying to retrieve a cache_key for a specific page instance. You could tweak it to add any other info from the instance, if you wanted to.
You use it like this:
from my_app.decorators import wagtail_cache_page from wagtail.wagtailcore.models import Page @wagtail_cache_page(60*10, cache="my_cache", key_prefix="MyPage", append_key_prefix_with_pk=True) class MyPage(Page): # class stuff here