In Django, how do you configure more than one cache in the CACHES setting and use a non-default cache from your code?
answer
- a dictionary of named entries
- one alias is mandatory
- BACKEND and LOCATION per entry
- caches[...] versus the cache proxy
basics
~10 sDjango's CACHES setting maps alias names to a dict with BACKEND, LOCATION and options; a 'default' alias is required. Code uses django.core.cache.cache for the default and caches['alias'] for any other.
solid answer
~30 s`CACHES` is a dict of dicts: each key is an **alias**, each value names a `BACKEND` class path plus optional `LOCATION`, `TIMEOUT`, `OPTIONS`, `KEY_PREFIX`, `VERSION` and `KEY_FUNCTION`. A `"default"` alias must exist, otherwise the system check `caches.E001` reports an error. In code, `from django.core.cache import cache` gives the default alias, and `from django.core.cache import caches` then `caches["reports"]` gives any other. `caches[alias]` returns the same object for repeated lookups in one thread and a separate instance per thread; an alias that is not configured raises `InvalidCacheBackendError`. If you never define `CACHES`, Django still has a cache: the default is `LocMemCache`.
code
python · 19 lines# settings.py
CACHES = {
"default": {
"BACKEND": "django.core.cache.backends.redis.RedisCache",
"LOCATION": "redis://127.0.0.1:6379/0",
"TIMEOUT": 600,
},
"reports": {
"BACKEND": "django.core.cache.backends.db.DatabaseCache",
"LOCATION": "report_cache",
"TIMEOUT": 3600,
},
}
# anywhere in the project
from django.core.cache import cache, caches
cache.set("homepage:banner", "Rain later today")
caches["reports"].set("monthly:2026-08", {"rows": 412})go deeper
Recall the shape: CACHES is a dict of aliases, 'default' is mandatory, cache is the default alias and caches['name'] reaches the others.
Explain the per-alias keys and their defaults, especially TIMEOUT 300 and LocMemCache as the implicit default backend.
Show why you would split aliases by lifetime, store or purge scope, and how session and middleware settings select an alias by name.
Frame alias design as blast-radius control: which data can be flushed together, and which data every process must share.
## What the CACHES setting is Django's cache framework (`django.core.cache`) is configured by one setting, **`CACHES`**. It is a nested dictionary: every top-level key is an **alias** (a name your code uses), and every value is a dictionary describing one cache connection. You can declare as many aliases as you like, but one of them must be called **`default`**. If a project never sets `CACHES`, Django falls back to its built-in default from `global_settings.py`: ```python CACHES = { "default": { "BACKEND": "django.core.cache.backends.locmem.LocMemCache", } } ``` So "we have no cache configured" is never quite true: there is always a local-memory cache behind `default`. ## The keys each alias accepts | Key | Default | What it means | |---|---|---| | `BACKEND` | none (required) | Dotted path to the backend class, e.g. `django.core.cache.backends.redis.RedisCache` | | `LOCATION` | `""` | Where the data lives: a Redis URL, `host:port` for Memcached, a table name, a directory, or a name for a local-memory store | | `TIMEOUT` | `300` | Default lifetime in seconds; `None` means never expire, `0` means expire immediately | | `OPTIONS` | `None` | Backend-specific extras; the Redis and Memcached backends pass them to the client library | | `KEY_PREFIX` | `""` | String mixed into every key this alias writes | | `VERSION` | `1` | Default version number mixed into every key | | `KEY_FUNCTION` | the built-in joiner | Dotted path to a function that builds the final key | Only `BACKEND` is truly needed; everything else has a default. ## Reaching an alias from code There are two public entry points in `django.core.cache`: - **`cache`** is a proxy for `caches["default"]`. It is what most application code imports. - **`caches`** is a dict-like handler. `caches["reports"]` returns the backend instance for the `reports` alias, creating it on first use. Two details interviewers like: 1. Within one thread, `caches["reports"] is caches["reports"]` is `True`; each thread gets its own backend instance, which keeps client objects thread-safe. 2. Asking for an alias that is not in `CACHES` raises **`InvalidCacheBackendError`** rather than silently handing you a dummy cache. Other parts of Django accept an alias name instead of a backend object: the `cache_page` decorator takes `cache=`, the cache middleware reads `CACHE_MIDDLEWARE_ALIAS`, and a cache-backed session store reads `SESSION_CACHE_ALIAS`. Each of those defaults to `"default"`. ## How Django builds a backend for an alias The `caches` handler creates backends lazily. The first time an alias is requested, Django copies that alias's dictionary, removes `BACKEND` and `LOCATION` from it, imports the class named by `BACKEND` and calls it as `BackendClass(location, params)`, where `params` is whatever is left (`TIMEOUT`, `OPTIONS`, `KEY_PREFIX` and so on). Consequences worth knowing: - A misspelt `BACKEND` path does not fail at import of `settings.py`; it fails on first use of that alias with `InvalidCacheBackendError` ("Could not find backend ..."). - Client libraries such as `redis-py` or `pymemcache` are imported only when a backend that needs them is built, so a project that never touches a Redis alias does not need the package installed. - Django connects a receiver to the `request_finished` signal that calls `close()` on every cache backend created so far, so backends that hold connections can release them at the end of each request; for most backends this is a no-op. ## Why teams use several aliases - **Different lifetimes**: a long-lived alias for rarely changing lookups next to a short-lived default. - **Different stores**: a shared Redis cache for data every worker must see, and a small `LocMemCache` alias for per-process memoisation of something cheap and immutable. - **Isolation**: a separate `KEY_PREFIX` or `LOCATION` so a bulk purge of one alias does not touch another's data. - **Tests**: overriding `CACHES` to `DummyCache` or `LocMemCache` for a test run without touching application code. ## Common mistakes - Removing the `default` alias while adding named ones: `manage.py check` then reports `caches.E001`, "You must define a 'default' cache in your CACHES setting." - Assuming a second `LocMemCache` alias is a separate store when both share the same `LOCATION`; local-memory stores are keyed by `LOCATION`, so give each one a distinct name. - Importing `cache` in code that should target another alias, so writes land in `default` and reads from `caches["reports"]` miss.
- What happens at startup if CACHES defines only a 'redis' alias and no 'default'?The system check framework reports `caches.E001`: "You must define a 'default' cache in your CACHES setting." Commands that run checks, such as `runserver` and `migrate`, stop on that error. `django.core.cache.cache` is a proxy for the `default` alias, so it has nothing to point at.
- What does caches['nightly'] do if 'nightly' is not a configured alias?It raises `InvalidCacheBackendError`, a subclass of `ImproperlyConfigured`. Django never substitutes a dummy backend for a missing alias, so a typo in an alias name fails loudly on first use rather than silently caching nothing.
saying these in an interview costs you the question
- Without a CACHES setting Django has no cache at all.
- The 'default' alias is optional as long as some alias exists.
- An unknown alias in caches[...] quietly returns a no-op cache.
- Each alias needs its own import, like from django.core.cache import reports.
- Two LocMemCache aliases are always separate stores whatever their LOCATION.