Correction re: Django caching

March 2, 2010

OK, so after reading the Django source code a little more closely, I found I was wrong. It absolutely is possible to invalidate the per-view caching. Here's a function I wrote to do it:

def expire_view_cache(view_name, args=[], namespace=None, key_prefix=None):
    """
    This function allows you to invalidate any view-level cache.
        view_name: view function you wish to invalidate or it's named url pattern
        args: any arguments passed to the view function
        namepace: if an application namespace is used, pass that
        key prefix: for the @cache_page decorator for the function (if any)
    """
    from django.core.urlresolvers import reverse
    from django.http import HttpRequest
    from django.utils.cache import get_cache_key
    from django.core.cache import cache
    # create a fake request object
    request = HttpRequest()
    # Loookup the request path:
    if namespace:
        view_name = namespace + ":" + view_name
    request.path = reverse(view_name, args=args)
    # get cache key, expire if the cached item exists:
    key = get_cache_key(request, key_prefix=key_prefix)
    if key:
        if cache.get(key):
            cache.set(key, None, 0)
        return True
    return False    

You can use it like this:

from project_utils import expire_view_cache

def invalidate_blog_index(sender, **kwargs):
    """Invalidate the view-level cache for the blog:index page"""   
    expire_view_cache("index", namespace="blog")   

post_save.connect(invalidate_blog_index, sender=Entry)

The is a pretty naive example, but basically whenever a blog entry is saved, the view-level cache for the blog index page is invalidated. Obviously you could be much more sophisticated with this. Per-view caching aside, I am quite sure that template fragment caching can only be invalidated when the TTL expires. That's a shame, but the per-view caching is far more useful anyway in my opinon.

Tagged with: , .