The Caching Framework

Caching is the technique of storing the result of an expensive operation so future requests can reuse it instead of recomputing it, trading a little staleness for a lot of speed.

Learn The Caching Framework in our free Django course — a beginner-friendly interactive lesson with worked examples, a practice exercise and a quick reference.

Part of the free Django course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.

In this lesson you'll use the low-level cache API ( set , get , add , delete ), see how a timeout makes entries expire, cache an entire view with @cache_page , cache a template fragment, and understand the backend choices from LocMem to Redis.

The low-level API treats the cache like a dictionary you can talk to from anywhere. You import the cache object and call set , get , add (write only if the key is new), and delete . The backend behind it is configured in CACHES , but your code stays the same.

The timeout argument is the key to caching. A value lives for that many seconds, then expires — a later get returns None and you recompute. This time-to-live (TTL) is what keeps cached data from going permanently stale.

You rarely write the cache-aside loop by hand. The @cache_page decorator caches a view's entire response for a given timeout, and the {' '} template tag caches just one fragment of a page while the rest stays dynamic.

Under the hood both decorators run the same cache-aside pattern you just simulated: check the cache by key, and only do the slow work on a miss.

A cache key must uniquely name what you stored. Fill in the blank so the key for user 42 becomes profile:42 .

You set a value with timeout=None (cache forever) and never invalidate it.

✅ Fix: give a sensible timeout , or call cache.delete(key) when the underlying data changes.

Your cache key was too generic, e.g. just "profile" for everyone.

✅ Fix: include the distinguishing input in the key, like "profile:" + str(user.id) .

❌ Cache "works" locally but not across servers

LocMemCache is per-process, so each worker has its own separate cache.

✅ Fix: use a shared backend like Redis or Memcached in production via the CACHES setting.

Write a @cached decorator that stores each result by its argument, so repeated calls with the same value skip the work — the same idea as @cache_page applied to a function.

Lesson complete — your pages are fast!

You can use the low-level API ( set , get , add , delete ), make entries expire with a timeout, cache a view with @cache_page , cache a fragment with {' '} , choose a backend, and design unique cache keys.

🚀 Up next: Custom Management Commands — write your own manage.py commands with BaseCommand .

Practice quiz

Which low-level call stores a value in the cache?

  • cache.put(key, value)
  • cache.store(key, value)
  • cache.add_value(key, value)
  • cache.set(key, value)

Answer: cache.set(key, value). cache.set(key, value, timeout) stores a value, overwriting any existing one.

How does cache.add() differ from cache.set()?

  • add() deletes the key
  • add() writes only if the key is new
  • add() never expires
  • add() reads the value

Answer: add() writes only if the key is new. add() only writes when the key is absent and returns False if it already exists.

What does cache.get() return for a missing or expired key?

  • None (or the provided default)
  • An empty string
  • A KeyError
  • 0

Answer: None (or the provided default). get() returns None on a miss, or the default you pass as the second argument.

Which decorator caches an entire view's response?

  • @cache_view
  • @cache
  • @cache_page(seconds)
  • @view_cache

Answer: @cache_page(seconds). @cache_page(timeout) caches a view's whole rendered response for the given seconds.

What does the timeout argument control?

  • The cache size
  • The backend type
  • The key length
  • How many seconds a value stays valid before expiring

Answer: How many seconds a value stays valid before expiring. timeout is the TTL: after it passes, a get returns None and you recompute.

Which template tag caches just one fragment of a page?

  • {% cache %}
  • {% fragment %}
  • {% store %}
  • {% memo %}

Answer: {% cache %}. The {% cache %} template tag caches a single fragment while the rest stays dynamic.

Why might caching work locally but not across servers?

  • Redis is too fast
  • The timeout is too short
  • LocMemCache is per-process, not shared
  • The key is too long

Answer: LocMemCache is per-process, not shared. LocMemCache is per-process; use a shared backend like Redis or Memcached in production.

What causes one user to see another user's cached data?

  • timeout=None
  • A cache key that is too generic
  • Using cache.add()
  • Using Redis

Answer: A cache key that is too generic. Include the distinguishing input (like a user id) in the key so each value is unique.

Which backend needs no setup and works out of the box for development?

  • Memcached
  • RabbitMQ
  • Redis
  • LocMemCache

Answer: LocMemCache. LocMemCache is the zero-config local-memory backend, fine for development.

How do you invalidate a cached value when its data changes?

  • cache.delete(key)
  • cache.expire_all()
  • cache.reset()
  • cache.flush_key()

Answer: cache.delete(key). cache.delete(key) removes the stale entry so it is recomputed next time.