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.