Setting a different expiry for Browser and Server Cache in Django

Tags: wagtail, cache

Perhaps you want your blog page to be cached server-side for a day or a week, as its content won't change.  However, you probably want browsers to check back with the server every 5 or 10 minutes, just in case it has....

This is pretty straight forward to do in Django (and Wagtail CMS).

You can use Django's site-wide caching or per-view caching as normal, setting the cache timeout to as long as you want (a day, a week etc). 


@cache_page(60*60*24)
def MyView
    # my view code here
    

Left like this, however, the browser would also cache the page for a day (week or whatever) - the same as the server.  We can use the following middleware to over ride the cache-control max-age and 'expires' headers, which will make sure the browser caches for a shorter period:


# in settings.py
RESPONSE_CACHE_SECONDS = 300

MIDDLEWARE_CLASSES = (
    'django_project.middleware.SetBrowserCacheTimeoutMiddleware',
    'django.middleware.cache.UpdateCacheMiddleware',
    # other middlwware here...
    'django.middleware.cache.FetchFromCacheMiddleware',
    )

# in django_project/middleware.py
from django.conf import settings
from django.utils.cache import patch_cache_control, get_max_age
from django.utils.http import http_date
import time


class SetBrowserCacheTimeoutMiddleware(object):
    def process_response(self, request, response):
        max_age = int(settings.RESPONSE_CACHE_SECONDS)
        current_max_age = get_max_age(response)
        if current_max_age:
            max_age = min(current_max_age, max_age)
        response['Expires'] = http_date(time.time() + max_age)
        patch_cache_control(response, max_age=max_age)
        return response
    

This middleware must be placed before (higher than) django's 'UpdateCacheMiddleware' (if you are using site-wide caching) - ideally the first in the list.  This means it will be the last middleware to effect the response, and so will not change the cache-control headers until after the server-side cache has been created.

NOTE

The middleware will set the max-age and 'expires' headers to the lower of your RESPONSE_CACHE_SECONDS and whatever those header values already are.

We don't worry about a 'no-cache' header because it will take precedence over any max-age or 'expires' headers in the browser.

Enjoy!

Loading comments...
';