django-redis is the Redis cache backend that doesn't suck. Maintained by Jazzband (they also maintain a bunch of other Python stuff that actually works).
Why Not Use Django's Built-in Cache?
Because it sucks ass for anything real. Django's default cache is fine for toy projects, but try doing atomic counters or cache invalidation patterns and you'll want to quit programming and become a fucking barista. You can't even reliably increment a counter without race conditions.
I spent 3 hours trying to implement a simple view counter with Django's cache before giving up. With django-redis it's literally cache.incr('views')
and it works atomically.
Why Not Raw Redis?
You could use raw Redis, but then you're writing all the Django integration yourself. Been there, done that, wanted to die for 3 weeks straight.
Plus django-redis handles all the connection pooling, serialization, and error recovery that you'll end up implementing anyway.
What Makes This Different?
- Actually works in production: I've been using this for 2 years without major issues
- Redis-specific features: INCR/DECR that don't break, proper TTL management, pattern-based deletions
- Compression that matters: Cut our Redis memory usage by 70% with lz4 compression
- Connection pooling that doesn't blow up: Unlike some other shitty packages that leak connections like a broken fire hydrant
Performance Reality
Switching from Django's default to this + Redis on our API:
- Response times: went from ~300ms to under 50ms for cached views
- Database load: cut by 70-80% on read-heavy endpoints
- Memory usage: about 30% higher than memcached, but compression helps
- Throughput: we went from handling ~100 req/s to 400+ req/s on the same hardware
The compression thing saves your ass if you're caching large objects. Use lz4 unless you're desperate for RAM, then use zstd.
Common Gotchas I Learned the Hard Way
Connection exhaustion: Set max_connections
properly or you'll hit Redis connection limits and your app will shit the bed during traffic spikes. Ask me how I know. Default is usually too low for production.
Serialization hell: Don't cache Django model instances directly - they have references to database connections and other unpickleable shit. Cache the .values()
data instead.
TTL weirdness: cache.set(key, value, 0)
means cache forever, not delete immediately. Spent 2 hours debugging why my cache wasn't expiring.
Redis version issues: Older Redis versions (pre-5.0) have different behavior for some commands. Check your version if weird shit happens.