Action0-Django-ACache
Django's Redis cache backend with async methods that are actually async: they
talk to the server through redis.asyncio instead of running the sync methods
in a worker thread.
Requires Python 3.11 or newer, Django 5.2 or newer and redis-py 5.0.1 or newer. Works with Redis and Valkey.
Full documentation including the API reference: https://laughinjar.github.io/action0-django-acache/
Status: early. Every async cache method is native and covered by tests (against fakeredis, and in CI against Redis 7/8 and Valkey 8/9); the API may still move.
Installation
pip install action0-django-acache # or: uv add action0-django-acache
pip install "action0-django-acache[hiredis]" # with the C parser
Usage
Swap the backend in your settings — everything else stays as with Django's Redis backend:
CACHES = {
"default": {
"BACKEND": "action0.django_acache.RedisCache",
"LOCATION": "redis://127.0.0.1:6379",
},
}
And await the cache in async code as usual:
from django.core.cache import cache
async def weather(request, city):
report = await cache.aget(f"weather:{city}")
if report is None:
report = await fetch_weather(city)
await cache.aset(f"weather:{city}", report, timeout=300)
...
Django's own RedisCache runs every one of these calls in a thread via
sync_to_async (and on Django 5.2 its aincr is not even atomic: a get, then
a set). Here aget, aset, aadd, atouch, adelete, ahas_key,
aget_many, aset_many, adelete_many, aincr and aclear are coroutines
on redis.asyncio, and aincr is a single INCRBY on the server.
The sync methods are Django's, untouched, and both sides write the same keys with the same serializer: sync and async code share one cache.
A few redis-py options come in a sync and an async variant. ASYNC_OPTIONS
overrides OPTIONS for the async side only — and a sync class or Retry that
would still reach the async side is an ImproperlyConfigured error naming the
fix:
CACHES = {
"default": {
"BACKEND": "action0.django_acache.RedisCache",
"LOCATION": "redis://127.0.0.1:6379",
"OPTIONS": {
"pool_class": "redis.BlockingConnectionPool",
"max_connections": 50,
},
"ASYNC_OPTIONS": {
"pool_class": "redis.asyncio.BlockingConnectionPool",
},
},
}
Under ASGI, Django creates a cache instance per request. The async connection
pools are therefore shared per event loop — all requests reuse the same
connections — and closed when the loop shuts down. aclose_pools() closes
them earlier:
from action0.django_acache import aclose_pools
await aclose_pools()
See the usage guide
for the details: which method sends which commands, every ASYNC_OPTIONS key,
the pool lifecycle, and a fakeredis setup for your tests.
The action0 namespace is simply the one the author likes to use for
personal projects.
Development
uv run pytest # tests (incl. doctests in src/), against fakeredis
uv run ruff check # lint
uv run ruff format # format
uv run mypy # type-check (strict)
uv run pyright # type-check
uv run ty check # type-check
REDIS_URL=redis://localhost:6379/15 uv run pytest runs the tests against a
real server instead — they flush that database.
AI disclosure
This library is developed with heavy use of AI coding tools: the code, tests, and documentation are largely written by Claude Code, working from the author's design brief and reviewed by the author. If that changes how much you want to rely on this package, that's a fair call — read the source, it's small.
License
MIT — see LICENSE.
Release files for action0-django-acache 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 | |
|---|---|---|---|
| action0_django_acache-0.1.0.tar.gz | 109.7 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| action0_django_acache-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 124.0 kB
Release files / action0_django_acache-0.1.0.tar.gz
| Download URL | action0_django_acache-0.1.0.tar.gz |
|---|---|
| Size | 109.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
438fd963013d7aa72be0e67345eba31cd4e00063d075e2baf123ab9c7aed1cb1
|
|
BLAKE2b-256 checksum How to use checksums |
8c1c2f7cf7fdefa4f8e146c5d79e86d517a6796787dcb65140ccd05eae9e5d23
|
| 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 Sep 26, 2026.
Transparency logRelease files / action0_django_acache-0.1.0-py3-none-any.whl
| Download URL | action0_django_acache-0.1.0-py3-none-any.whl |
|---|---|
| Size | 14.3 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
e578508e36b0333bf941aad2fc0455fed363eb7b83156f5501a08e9c15d168fd
|
|
BLAKE2b-256 checksum How to use checksums |
026626571c5758a8e9e2fc3ac2d8f67269cc8b392346dda9bf95d97b1a647a3e
|
| 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 Sep 26, 2026.
Transparency log