Skip to content

API Reference

Cache Methods

Standard Django Cache Methods

All standard Django cache methods are supported:

Method Description
get(key, default=None) Get a value
set(key, value, timeout=DEFAULT) Set a value
add(key, value, timeout=DEFAULT) Set only if key doesn't exist
delete(key) Delete a key
touch(key, timeout=DEFAULT) Update timeout on a key
get_many(keys) Get multiple values
set_many(data, timeout=DEFAULT) Set multiple values
delete_many(keys) Delete multiple keys
get_or_set(key, default, timeout=DEFAULT) Get value or set default
clear() Clear the cache
has_key(key) Check if key exists
incr(key, delta=1) Increment a value
decr(key, delta=1) Decrement a value
incr_version(key, delta=1) Increment key version
decr_version(key, delta=1) Decrement key version
close() Close connections

Extended Methods

django-cachex adds these extended methods:

Method Description
ttl(key) Get TTL in seconds (None = no expiry, -2 = not found)
pttl(key) Get TTL in milliseconds (None = no expiry, -2 = not found)
expire(key, timeout) Set expiration in seconds
pexpire(key, timeout) Set expiration in milliseconds
expireat(key, when) Set expiration at datetime
pexpireat(key, when) Set expiration at datetime (ms precision)
expiretime(key) Absolute Unix timestamp (seconds) when the key expires
persist(key) Remove expiration
type(key) Get the data type of a key
lock(key, ...) Get a distributed lock
keys(pattern) Get keys matching pattern
iter_keys(pattern) Iterate keys matching pattern
scan(cursor, pattern, count) Single SCAN iteration
delete_pattern(pattern) Delete keys matching pattern
rename(src, dst) Rename a key
renamenx(src, dst) Rename key only if dest doesn't exist

Hash Methods

Hash operations for field-value data structures:

Method Description
hset(key, field=None, value=None, mapping=None, items=None) Set hash field(s); pass field/value, a mapping dict, or a flat items list
hdel(key, *fields) Delete hash field(s)
hexists(key, field) Check if hash field exists
hget(key, field) Get a hash field value
hgetall(key) Get all fields and values in a hash
hkeys(key) Get all field names in a hash
hincrby(key, field, amount=1) Increment hash field by integer
hincrbyfloat(key, field, amount=1.0) Increment hash field by float
hlen(key) Get number of fields in hash
hmget(key, *fields) Get multiple hash field values
hsetnx(key, field, value) Set hash field only if it doesn't exist
hvals(key) Get all values in a hash

Set Methods

Set operations for unordered collections of unique elements:

Method Description
sadd(key, *members) Add member(s) to set
srem(key, *members) Remove member(s) from set
smembers(key) Get all members of set
sismember(key, member) Check if member exists in set
smismember(key, *members) Check if multiple members exist
scard(key) Get number of members
spop(key, count=None) Remove and return random member(s)
srandmember(key, count=None) Get random member(s) without removing
smove(src, dst, member) Move member between sets
sdiff(keys) Get difference of sets
sdiffstore(dest, keys) Store difference of sets
sinter(keys) Get intersection of sets
sinterstore(dest, keys) Store intersection of sets
sunion(keys) Get union of sets
sunionstore(dest, keys) Store union of sets
sscan(key, cursor=0, ...) Incrementally iterate set members
sscan_iter(key, ...) Iterate over set members using SSCAN

keys on the multi-key set operations takes a single key or a sequence of them, not varargs. sdiff(["a", "b"]), not sdiff("a", "b"): the second positional argument is version.

Sorted Set Methods

Sorted set operations for scored, ordered collections:

Method Description
zadd(key, mapping, *, nx, xx, ch, gt, lt) Add member(s) with scores
zcard(key) Get number of members
zcount(key, min_score, max_score) Count members with scores in range
zincrby(key, amount, member) Increment member's score
zrange(key, start, end, ...) Get members by index range
zrevrange(key, start, end, ...) Get members by index range (descending)
zrangebyscore(key, min_score, max_score, ...) Get members by score range
zrevrangebyscore(key, max_score, min_score, ...) Get members by score range (descending)
zrank(key, member) Get member's rank (ascending)
zrevrank(key, member) Get member's rank (descending)
zrem(key, *members) Remove member(s)
zremrangebyrank(key, start, end) Remove members by rank range
zremrangebyscore(key, min_score, max_score) Remove members by score range
zscore(key, member) Get member's score
zmscore(key, *members) Get multiple members' scores
zpopmin(key, count=1) Remove and return members with lowest scores
zpopmax(key, count=1) Remove and return members with highest scores

List Methods

List operations for ordered, indexable collections:

Method Description
llen(key) Get list length
lpush(key, *values) Prepend value(s) to list
rpush(key, *values) Append value(s) to list
lpop(key) Remove and return first element
rpop(key) Remove and return last element
lindex(key, index) Get element by index
lrange(key, start, end) Get elements in range
lset(key, index, value) Set element at index
ltrim(key, start, end) Trim list to range
lrem(key, count, value) Remove elements equal to value
lpos(key, value, ...) Find element position in list
linsert(key, where, pivot, value) Insert value before or after pivot
lmove(src, dst, wherefrom, whereto) Atomically move element between lists
blpop(keys, timeout=0) Blocking pop from head of list
brpop(keys, timeout=0) Blocking pop from tail of list
blmove(src, dst, timeout, ...) Blocking move between lists

blpop and brpop take keys the same way: one key or a sequence, followed by timeout.

Stream Methods

Append-only log structure with consumer groups:

Method Description
xadd(key, fields, entry_id="*", maxlen=None, ...) Append an entry, returning its ID
xlen(key) Number of entries in the stream
xrange(key, start="-", end="+", count=None) Range of entries (forward)
xrevrange(key, end="+", start="-", count=None) Range of entries (reverse)
xread(streams, count=None, block=None) Read new entries from one or more streams
xtrim(key, maxlen=None, approximate=True, minid=None, ...) Cap stream length
xdel(key, *entry_ids) Delete entries by ID
xinfo_stream(key, full=False) Stream metadata
xinfo_groups(key) Consumer group metadata
xinfo_consumers(key, group) Per-consumer metadata for a group
xgroup_create(key, group, entry_id="$", mkstream=False) Create a consumer group
xgroup_destroy(key, group) Drop a consumer group
xgroup_setid(key, group, entry_id) Re-anchor a consumer group's read position
xgroup_delconsumer(key, group, consumer) Drop a consumer from a group
xreadgroup(group, consumer, streams, count=None, block=None) Read entries as a group consumer
xack(key, group, *entry_ids) Acknowledge processed entries
xpending(key, group, ...) Inspect pending (unacked) entries
xclaim(key, group, consumer, min_idle_time, entry_ids, ...) Claim pending entries
xautoclaim(key, group, consumer, min_idle_time, ...) Auto-claim entries idle longer than threshold

All methods have an a* async counterpart (e.g. axadd, axreadgroup).

Lua Script Methods

Execute Lua scripts with optional key prefixing and value encoding/decoding:

Method Description
eval_script(script, *, keys, args, ...) Execute a Lua script
aeval_script(script, *, keys, args, ...) Execute a Lua script (async)

eval_script / aeval_script

result = cache.eval_script(
    script,  # Lua script source code
    keys=(),  # KEYS to pass to script
    args=(),  # ARGV to pass to script
    pre_hook=None,  # Pre-processing hook: (helpers, keys, args) -> (keys, args)
    post_hook=None,  # Post-processing hook: (helpers, result) -> result
    version=None,  # Key version for prefixing
)

Pre-built Hooks

Hook Description
keys_only_pre Prefix keys, leave args unchanged
full_encode_pre Prefix keys AND encode all args
decode_single_post Decode a single returned value
decode_list_post Decode a list of returned values

Pass post_hook=None (the default) when no decoding is needed.

ScriptHelpers

The helpers object passed to pre/post hooks:

Attribute/Method Description
make_key(key, version) Apply cache key prefix
make_keys(keys) Prefix multiple keys
encode(value) Encode a value (serialize + compress)
encode_values(values) Encode multiple values
decode(value) Decode a value
decode_values(values) Decode multiple values
version Current key version

Set Method Options

cache.set(key, value, timeout=300, nx=False, xx=False, get=False)
Parameter Description
timeout Expiration in seconds (None = never, 0 = immediate)
nx Only set if key doesn't exist (SETNX)
xx Only set if key exists
get Return the previous value (atomic get-and-set)

Async Methods

Standard Django cache methods have async versions on the cache object:

# Sync
value = cache.get("key")

# Async
value = await cache.aget("key")
  • aadd, aget, aset, adelete, atouch, aget_many, aset_many, adelete_many
  • ahas_key, aincr, adecr, aget_or_set, aclear, aclose
  • aincr_version, adecr_version
  • aeval_script

Extended methods (data structures, TTL, patterns) have async versions directly on the cache. Both forms apply key prefixing and the serializer/compressor pipeline:

# Sync
cache.hset("hash", "field", "value")

# Async
await cache.ahset("hash", "field", "value")

For raw access that skips prefixing/serialization, use cache.adapter (e.g. await cache.adapter.aget(prefixed_key)).

  • attl, apttl, aexpire, apexpire, aexpireat, apexpireat, apersist
  • akeys, aiter_keys, adelete_pattern
  • ahset, ahdel, ahexists, ahget, ahgetall, ahincrby, ahincrbyfloat, ahkeys, ahlen, ahmget, ahsetnx, ahvals
  • asadd, asrem, asmembers, asismember, asmismember, ascard, aspop, asrandmember, asmove, asdiff, asdiffstore, asinter, asinterstore, asunion, asunionstore
  • azadd, azcard, azcount, azincrby, azrange, azrevrange, azrangebyscore, azrevrangebyscore, azrank, azrevrank, azrem, azremrangebyrank, azremrangebyscore, azscore, azmscore, azpopmin, azpopmax
  • allen, alpush, arpush, alpop, arpop, alindex, alrange, alset, altrim, alrem, alpos, almove, alinsert, ablpop, abrpop, ablmove
  • asscan, asscan_iter

Raw Client Access

client = cache.get_client(write=True)
Parameter Description
write Get write connection for primary (default: False)

Returns the underlying client object. The concrete type depends on which adapter is configured:

Backend get_client() returns
ValkeyCache (valkey-py) valkey.Valkey
RedisCache (redis-py) redis.Redis
RedisRsCache (redis-rs) django_cachex.adapters.RedisRsAdapter (the adapter is its own multiplexed client)
ValkeyGlideCache (valkey-glide) glide_sync.GlideClient

The four objects expose comparable command surfaces but are not interchangeable types; code that pins to one adapter for type-narrowing or vendor-specific calls won't work against the others. For adapter-portable code use the cache API directly; reach for get_client() only as an escape hatch, since it bypasses the configured key prefix, version, serializer, and compressor.

The async equivalent is get_async_client(), which is async def and returns the adapter's async client.

Lock Interface

lock = cache.lock(key, lease=None, sleep=0.1, blocking=True, timeout=None)
Parameter Description
key Lock name
lease TTL of the held lock; the lock is auto-released after this many seconds (no auto-release if None)
sleep Time between acquire attempts
blocking Wait for lock if held
timeout Max time acquire() will wait before giving up (no upper bound if None)

acquire() accepts the same blocking / timeout arguments to override the defaults set on the lock object:

lock = cache.lock("mylock", lease=30)
if lock.acquire(timeout=5):  # wait up to 5s
    ...

Compatible with threading.Lock:

# Context manager
with cache.lock("mylock"):
    do_work()

# Manual acquire/release
lock = cache.lock("mylock")
if lock.acquire():
    try:
        do_work()
    finally:
        lock.release()

Async lock

alock() is async def (parallel to apipeline()):

# Context manager
async with await cache.alock("mylock"):
    await do_work()

# Manual acquire/release
lock = await cache.alock("mylock")
if await lock.acquire():
    try:
        await do_work()
    finally:
        await lock.release()

Cluster mode rejects lock() and alock() on every adapter: the release script runs via EVALSHA, which cluster routes to replicas, so release() would fail and the key would stay set until its lease expired. Both raise NotSupportedError. Use semaphore() instead, which colocates its keys under a {name} hash tag.

Semaphore Interface

sem = cache.semaphore(key, capacity, *, weight=1, version=None, lease=None, timeout=None)

Return a weighted semaphore for concurrency gating. Use as a context manager.

with cache.semaphore("image-convert", capacity=4):
    # Up to 4 callers may hold this semaphore concurrently.
    convert(...)

# Weighted: claim 100 of a 500 budget.
with cache.semaphore("memory-heavy", weight=100, capacity=500, lease=300):
    convert_huge(...)
Parameter Description
key Logical name of the semaphore. Callers with the same name share budget.
capacity Total budget. The first caller establishes capacity. Subsequent callers passing a different value update it on every backend; the local backend additionally emits a RuntimeWarning (the RESP backend updates silently).
weight How much of the capacity this caller claims (default 1, i.e. counting semaphore).
version Optional cache version namespace.
lease TTL of the held claim in seconds. Required for the RESP backend (auto-reclaim if the holder crashes); accepted but ignored on the local backend.
timeout Max time acquire() will wait before raising SemaphoreTimeoutError. None blocks indefinitely.

acquire() accepts blocking and timeout to override the defaults set on the semaphore object. release() returns the claim to the pool; extend(seconds) bumps the TTL on RESP backends for tasks that may legitimately exceed their original lease.

sem = cache.semaphore("mysem", capacity=4, lease=30)
if sem.acquire(timeout=5):
    try:
        do_work()
    finally:
        sem.release()

Async semaphore

asemaphore() is async def (parallel to alock()):

# Context manager
async with await cache.asemaphore("mysem", capacity=4, lease=30):
    await do_work()

# Manual acquire/release
sem = await cache.asemaphore("mysem", capacity=4, lease=30)
if await sem.aacquire():
    try:
        await do_work()
    finally:
        await sem.arelease()

The awaitable methods are aacquire() and arelease(). acquire() and release() are the sync pair and are still present on the same object, so await sem.acquire() runs the sync acquire and then raises TypeError on the returned bool, leaving the claim held until its lease expires.

Sync and async callers on the same cache instance share state for a given name.

Backends:

  • LocMemCache uses an in-process FIFO deque. FIFO fairness is strict within the process; lease is accepted but ignored.
  • RESP backends (RedisCache, ValkeyCache, RedisRsCache, ValkeyGlideCache, ...) use Lua scripts. FIFO fairness is best-effort across processes (head-of-queue check plus jittered polling).

Cluster mode is supported on RESP backends: all keys for one semaphore name carry a {name} hash tag so they colocate on the same slot.

Pipelines

Batch multiple operations for efficiency. Queueing methods (set, hset, lpush, ...) stay synchronous in both wrappers; only execute() performs I/O.

Sync

with cache.pipeline() as pipe:
    pipe.set("key1", "value1")
    pipe.set("key2", "value2")
    pipe.hset("hash", "field", "value")
    results = pipe.execute()

Async

async with await cache.apipeline() as pipe:
    pipe.set("key1", "value1")
    pipe.hset("hash", "field", "value")
    results = await pipe.execute()

apipeline() is async def so adapters whose async-client construction is itself awaitable (e.g. valkey-glide) can resolve the client before returning the wrapper. Queueing methods stay synchronous; only apipeline() and execute() need to be awaited.

Single-key commands are available on the pipeline. The multi-key helpers (set_many, get_many, delete_many), the read-modify-write helpers (get_or_set, add, touch, has_key), and the scanning helpers (keys, scan, delete_pattern, clear) are not: queue their underlying commands instead. Results are returned as a list in the same order as the commands.

Clearing keys

Method Description
clear() / aclear() Remove only this cache's keys (KEY_PREFIX + VERSION). Implemented as delete_pattern("*").
flush_db() / aflush_db() FLUSHDB: remove all keys in the underlying Redis/Valkey database, regardless of prefix.

clear() is safe when multiple apps share a Redis database. Use flush_db() only when you really want to flush the whole database and not the configured Django namespace.

Settings Reference

Cache OPTIONS

Option Description
serializer Serializer class or list for fallback
compressor Compressor class or list for fallback
password Server password
socket_connect_timeout Connection timeout
socket_timeout Read/write timeout
pool_class Custom connection pool class (sync)
async_pool_class Custom connection pool class (async)
parser_class Custom RESP parser class
stampede_prevention True / False / dict (buffer, beta, delta); see StampedeConfig
sentinels Sentinel server list (for Sentinel backends)
sentinel_kwargs Sentinel configuration

StampedeConfig

django_cachex.StampedeConfig(buffer=60, beta=1.0, delta=1.0), frozen dataclass that tunes the TTL-based XFetch stampede-prevention algorithm. Pass it to OPTIONS["stampede_prevention"] to apply globally, or to the stampede_prevention= kwarg on get/set/get_many/set_many/add/ touch/get_or_set, and their a-prefixed async counterparts, for per-call overrides. touch uses it to decide whether the refreshed TTL gets the buffer added back.

Field Default Description
buffer 60 Seconds added to TTL on writes; defines the early-recompute window.
beta 1.0 Multiplier on the recompute probability; higher = recompute earlier.
delta 1.0 Recompute-cost estimate (seconds); larger = recompute earlier.

Exceptions

All importable from the package root (django_cachex). Every exception subclasses CachexError, so one except CachexError handles any library failure.

Exception Description
CachexError Base class for every exception raised by django-cachex.
WrongTypeError Operation applied to a key holding the wrong RESP type (subclass of TypeError). Mirrors Redis WRONGTYPE; raised consistently across LocMem, redis-py, valkey-py, valkey-glide, and the Rust adapter.
CompressorError Compression or decompression failed. Triggers the configured compressor fallback chain.
SerializerError Serialization or deserialization failed. Triggers the serializer fallback chain.
NotSupportedError Operation is not supported by this backend (e.g. lpush on TieredCache).
LockError A lock operation failed (couldn't acquire, releasing an unlocked lock, ...).
LockNotOwnedError Releasing or extending a lock the caller no longer owns (expired or stolen). Subclass of LockError.
SemaphoreError A semaphore operation failed (e.g. re-acquiring before release).
SemaphoreTimeoutError timeout elapsed before the semaphore could be acquired. Subclass of SemaphoreError.