About Invalidating Django Page Cache

When you use @cache_page decorator for views, the cache key will be based on these variables:

  • cache key base string (e.g. "views.decorators.cache.cache_page")
  • settings.CACHE_MIDDLEWARE_KEY_PREFIX
  • request method (e.g. "GET")
  • hashed full URL
  • a hash of predefined request headers
  • request language code
  • active timezone

Use the following utility function to delete such cache entry for a specific cached view:

def invalidate_cache_for_path(url_path):
    from django.conf import settings
    from django.core.cache import cache
    from django.http import HttpRequest
    from django.utils.cache import get_cache_key

    website_url = getattr(settings, "WEBSITE_URL", "")
    if not website_url:
        return

    parsed = urlparse(website_url)
    key_prefix = getattr(settings, "CACHE_MIDDLEWARE_KEY_PREFIX", "")

    # SECURE_PROXY_SSL_HEADER is set in production, so Django reads
    # HTTP_X_FORWARDED_PROTO from META and returns the correct scheme.
    dummy = HttpRequest()
    dummy.path = url_path
    dummy.META = {
        "HTTP_HOST": parsed.netloc,
        "HTTP_X_FORWARDED_PROTO": parsed.scheme,
    }

    deleted_keys = []
    for lang_code, _ in settings.LANGUAGES:
        dummy.LANGUAGE_CODE = lang_code
        cache_key = get_cache_key(dummy, key_prefix=key_prefix)
        if cache_key:
            cache.delete(cache_key)
            deleted_keys.append(cache_key)

For the decorator to work correctly, you also need these Django settings:

  • WEBSITE_URL (e.g. "https://www.djangotricks.com").
  • SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https") - without it, the dummy request produces http://, the URL hash is different, and get_cache_key returns None.
  • LANGUAGES reduced to only those languages that you use for translations.

So if you have a view:

from django.shortcuts import render, get_object_or_404
from django.views.decorators.cache import cache_page
from django.contrib.auth.models import User

@cache_page(60 * 15)  # Cache the view for 15 minutes
def user_profile_view(request, username):
    user = get_object_or_404(User, username=username)
    context = {
        "user": user,
    }
    return render(request, "pages/user_profile.html", context)

And URL path:

from django.urls import path
from .views import user_profile_view

urlpatterns = [
    path("users/<str:username>/", user_profile_view, name="user_profile"),
]

And that user changes their user information, you can invalidate the cache and make the page show fresh information with:

invalidate_cache_for_path(
    reverse("user_profile", kwargs={"username": user.username})
)

Tips and Tricks Programming Caching Django 6.x Django 5.2 Django 4.2 Memcached Redis Cache

Django/Python Consulting

If you have a specific Django challenge or integration you'd like to solve, I'd be happy to help. Book a free 30-minute call to discuss your project, see if we're a good fit, and explore the best approach for your needs. After the call, you'll receive a tailored cost estimate based on what we discuss.