aiodrf-async-cache
Native async Redis and Valkey backends for Django's cache framework, built on the async clients of redis-py and valkey-py. It requires Python 3.12+ and Django 5.2+, and depends on neither Django REST framework nor django-aiodrf.
pip install "aiodrf-async-cache[redis]" # redis-py
pip install "aiodrf-async-cache[valkey]" # valkey-py
Usage
# settings.py
CACHES = {
"default": {
"BACKEND": "aiodrf_async_cache.redis.AsyncRedisCache",
"LOCATION": "redis://localhost:6379/1",
"TIMEOUT": 300,
"KEY_PREFIX": "myapp",
"VERSION": 1,
},
}
For Valkey, use aiodrf_async_cache.valkey.AsyncValkeyCache with a
valkey:// URL; it does not need django-valkey.
from django.core.cache import caches
async def cached_total():
cache = caches["default"]
await cache.aset("total", 42)
return await cache.aget("total")
The backends subclass Django's BaseCache and implement its
asynchronous API:
aadd, aget, aset, atouch, adelete, aget_many, aset_many,
adelete_many, ahas_key, aget_or_set, aincr, adecr,
aincr_version, adecr_version, aclear and aclose, with Django's
parameter names, defaults, and key, version and timeout rules. A missing
value differs from a cached None, and aset_many returns the keys it could
not set. Without a timeout the entry uses TIMEOUT; None keeps it, and
zero or a negative timeout expires it at once. KEY_FUNCTION and a
subclass's key validation apply as in Django.
Configuration and backend lookup stay in Django, as its
cache design
expects: there is no service registry and no patch. The default codec is
Django's RedisSerializer, so integers stay usable by the server's atomic
increments. Codec work for a batch runs in one worker call, and callbacks
keep their order.
The backends are async only. Django's synchronous cache middleware, template
fragment caching and other synchronous callers need a separate synchronous
cache alias. Django 6.1's cache middleware is not asynchronous; the
middleware in aiodrf_async_cache.middleware applies Django's page-cache
policy with these backends.
Connection ownership
A backend's client belongs to the first event loop that uses it: close it on
that loop with await cache.aclose() once its users are done, and do not
share a backend between event loops. cache_lifespan() builds a backend of
its own from a Django cache alias and closes it on exit, for resources that a
worker owns:
from contextlib import asynccontextmanager
from aiodrf_async_cache.lifespan import cache_lifespan
@asynccontextmanager
async def resources():
async with cache_lifespan("default") as cache:
yield cache
The context manager works with any lifespan owner. AsyncCacheMiddleware
reads the cache from the lifespan of
aiodrf-asgi-lifespan
(the lifespan extra) by default: set
DJANGO_LIFESPAN = "project.lifecycle.resources" and serve its ASGI
application. When the lifespan holds several clients, subclass the
middleware and return the cache from get_cache(request); such a subclass
does not need the lifespan package.
Options and limits
OPTIONS accepts:
callback_mode:"thread"(the default) runs synchronous callbacks in a worker thread;"inline"runs them on the event loop, for callbacks that never block.serializer: a dotted path, a class or an object withdumpsandloads.max_connections(20),async_pool_classandasync_pool_kwargs.
Other options go to the driver's async client. Async callbacks are awaited,
and so is an awaitable that a synchronous callback returns. Decoded text
responses (decode_responses) are refused: the codecs need bytes.
topology="sentinel" needs sentinels=[(host, port), ...] and takes the
service name as LOCATION; sentinel_kwargs configures the discovery
connections. topology="cluster" takes a seed URL as LOCATION and sends
batches as separate commands per key, so their keys may be in different
slots; such batches are not atomic. aclear() empties the whole selected
database, or every primary in a cluster, whatever the KEY_PREFIX: use it on
a dedicated cache database only.
The msgspec extra provides aiodrf_async_cache.codecs.MsgspecCodec. Its
typed mode stores values differently from Django's default pickle codec and
does not suit cached pages or integer counters. aincr and adecr need a
codec that declares raw integer support.
The django-valkey extra provides
aiodrf_async_cache.django_valkey.LifespanConnectionFactory, which gives
django-valkey's own backend pools owned by one lifespan. It is independent of
the native backends.
Contributing
See CONTRIBUTING.md.
Metadata
Release files for aiodrf-async-cache 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| aiodrf_async_cache-0.1.0.tar.gz | 28.5 kB | With provenance | Details for aiodrf_async_cache-0.1.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| aiodrf_async_cache-0.1.0-py3-none-any.whl | Python 3 | none | any | Details for aiodrf_async_cache-0.1.0-py3-none-any.whl |
Total release size: 44.1 kB
Release files / aiodrf_async_cache-0.1.0.tar.gz
| Download URL | aiodrf_async_cache-0.1.0.tar.gz |
|---|---|
| Size | 28.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
09ea64ef78eada615ebc496bcea63ef4e2fe6134556a780b8780c1403fb88319
|
|
BLAKE2b-256 checksum How to use checksums |
d6be9beb1b4dbe9664b0fcd7babcd4ca0b10c2ac481ad7cf93bd6701f490a9c7
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 3, 2026.
Transparency logRelease files / aiodrf_async_cache-0.1.0-py3-none-any.whl
| Download URL | aiodrf_async_cache-0.1.0-py3-none-any.whl |
|---|---|
| Size | 15.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
f1fa505cc1e1078d367302025a71f139e312586215a56e23964f7cf0b0c275c2
|
|
BLAKE2b-256 checksum How to use checksums |
bded140a231c71aca52fff2c032258f1a77b51ef28189a5c81f46b366be1d262
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 3, 2026.
Transparency logSecurity for aiodrf-async-cache 0.1.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
Both files in this release have been uploaded with provenance metadata.
Attestation for aiodrf_async_cache-0.1.0.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 3, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.