If you are a Django developer, you are probably familiar with django.core.cache (server-side caching). However, Django also provides another powerful toolkit called django.utils.cache that allows for effective control of HTTP caching. This module focuses on managing essential HTTP headers that reduce server load and enhance user experience.

In this post, we will examine the key features and usage of django.utils.cache.


django.core.cache vs django.utils.cache



First, let's clarify the differences.

  • django.core.cache (server-side cache):

    • Stores results of database queries, complex calculations, parts of templates, etc., in server memory (RAM), Redis, Memcached, etc.
    • Purpose: Reduces computational load on the server to increase response generation speed.
  • django.utils.cache (HTTP cache / client-side cache):

    • Sets HTTP response headers like Cache-Control, Vary, ETag, Last-Modified.
    • Purpose: Instructs browsers or proxy servers to cache the response, allowing them to use the cached response instead of making a new request to the server when the same request occurs.

In simple terms, core.cache caches data, while utils.cache controls how to cache HTTP responses.


Key Decorators and Features

The django.utils.cache module is primarily used as decorators to be applied to views.

1. @cache_control

This is the most basic yet powerful decorator that allows fine control over the Cache-Control HTTP header.

  • max_age: The duration (in seconds) for which the cache is valid. Browsers will use the cached version for this duration.
  • public=True: Indicates that the response can be stored in public caches (e.g., CDN, proxy).
  • private=True: Indicates that the response should only be stored in private caches, such as the user's browser. (Typically used with max_age)
  • no_cache: Forces the browser to validate with the server before using the cached version.
  • no_store: Ensures that the response is never cached.

Example:

# views.py
from django.utils.cache import cache_control

# Cache this view's response for 1 hour (3600 seconds) in the browser
@cache_control(max_age=3600)
def my_public_view(request):
    # ...
    return response

# This view contains sensitive user information, so it should be stored only in private cache (browser) for 30 minutes
@cache_control(private=True, max_age=1800)
def user_profile_view(request):
    # ...
    return response

2. @never_cache

As the name suggests, this decorator is used to ensure that the response of this view is never cached.

It adds the Cache-Control: max-age=0, no-cache, no-store, must-revalidate header to strongly instruct the browser not to cache the response.

Example: (commonly used for payment pages, important form submission pages, etc.)

# views.py
from django.utils.cache import never_cache

@never_cache
def sensitive_form_view(request):
    # ...
    return response

This decorator is used to set the Vary header. The Vary header plays an important role in indicating how cached responses can vary based on certain conditions.

For example, using @vary_on_headers('User-Agent') allows different HTML to be served based on mobile and desktop User-Agent, making the cache distinguish between the two.

@vary_on_cookie is used when the content of the view varies based on cookie values (e.g., when the login/logout state varies according to session cookies).

Example:

# views.py
from django.views.decorators.vary import vary_on_headers, vary_on_cookie

# Store cache separately based on User-Agent (mobile/desktop) and Accept-Language (language settings)
@vary_on_headers('User-Agent', 'Accept-Language')
def content_view(request):
    # ...
    return response

# View with content that varies based on cookies (session)
@vary_on_cookie
def user_specific_view(request):
    # ...
    return response

Summary



django.utils.cache is a core module that supports Django in adhering to HTTP standards and finely handling client-side caching.

Properly setting Cache-Control and Vary headers is a key strategy for dramatically reducing server traffic and allowing users to experience faster loading speeds. Utilizing this module's decorators, especially for static content or pages that do not change frequently, can lead to significant performance improvements.