Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,4 @@ dump.rdb
.coverage
coverage.xml
cobertura.xml
CLAUDE.md
3 changes: 3 additions & 0 deletions .ruff.toml
Original file line number Diff line number Diff line change
Expand Up @@ -178,3 +178,6 @@ ban-relative-imports = "all"

# pickle is used on purpose and its use is discouraged
"django_redis/serializers/pickle.py" = ["S301"]

# min/max are official Redis parameter names matching redis-py API
"django_redis/client/mixins/sorted_sets.py" = ["A002"]
1 change: 1 addition & 0 deletions changelog.d/797.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add sorted set operations (zadd, zrange, zrem, etc.) and mixins for RedisCache
57 changes: 57 additions & 0 deletions django_redis/cache.py
Original file line number Diff line number Diff line change
Expand Up @@ -278,3 +278,60 @@ def hkeys(self, *args, **kwargs):
@omit_exception
def hexists(self, *args, **kwargs):
return self.client.hexists(*args, **kwargs)

# Sorted Set Operations
@omit_exception
def zadd(self, *args, **kwargs):
return self.client.zadd(*args, **kwargs)

@omit_exception
def zcard(self, *args, **kwargs):
return self.client.zcard(*args, **kwargs)

@omit_exception
def zcount(self, *args, **kwargs):
return self.client.zcount(*args, **kwargs)

@omit_exception
def zincrby(self, *args, **kwargs):
return self.client.zincrby(*args, **kwargs)

@omit_exception
def zpopmax(self, *args, **kwargs):
return self.client.zpopmax(*args, **kwargs)

@omit_exception
def zpopmin(self, *args, **kwargs):
return self.client.zpopmin(*args, **kwargs)

@omit_exception
def zrange(self, *args, **kwargs):
return self.client.zrange(*args, **kwargs)

@omit_exception
def zrangebyscore(self, *args, **kwargs):
return self.client.zrangebyscore(*args, **kwargs)

@omit_exception
def zrank(self, *args, **kwargs):
return self.client.zrank(*args, **kwargs)

@omit_exception
def zrem(self, *args, **kwargs):
return self.client.zrem(*args, **kwargs)

@omit_exception
def zremrangebyscore(self, *args, **kwargs):
return self.client.zremrangebyscore(*args, **kwargs)

@omit_exception
def zrevrange(self, *args, **kwargs):
return self.client.zrevrange(*args, **kwargs)

@omit_exception
def zrevrangebyscore(self, *args, **kwargs):
return self.client.zrevrangebyscore(*args, **kwargs)

@omit_exception
def zscore(self, *args, **kwargs):
return self.client.zscore(*args, **kwargs)
3 changes: 2 additions & 1 deletion django_redis/client/default.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
from redis.typing import AbsExpiryT, EncodableT, ExpiryT, KeyT, PatternT

from django_redis import pool
from django_redis.client.mixins import SortedSetMixin
from django_redis.exceptions import CompressorError, ConnectionInterrupted
from django_redis.util import CacheKey

Expand All @@ -40,7 +41,7 @@ def glob_escape(s: str) -> str:
return special_re.sub(r"[\1]", s)


class DefaultClient:
class DefaultClient(SortedSetMixin):
def __init__(self, server, params: dict[str, Any], backend: BaseCache) -> None:
self._backend = backend
self._server = server
Expand Down
4 changes: 4 additions & 0 deletions django_redis/client/mixins/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
from django_redis.client.mixins.protocols import ClientProtocol
from django_redis.client.mixins.sorted_sets import SortedSetMixin

__all__ = ["ClientProtocol", "SortedSetMixin"]
33 changes: 33 additions & 0 deletions django_redis/client/mixins/protocols.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
from typing import Any, Optional, Protocol, Union

from redis import Redis
from redis.typing import KeyT


class ClientProtocol(Protocol):
"""
Protocol for client methods required by mixins.

Any class using django-redis mixins must implement these methods.
"""

def make_key(
self,
key: KeyT,
version: Optional[int] = None,
prefix: Optional[str] = None,
) -> KeyT:
"""Create a cache key with optional version and prefix."""
...

def encode(self, value: Any) -> Union[bytes, int]:
"""Encode a value for storage in Redis."""
...

def decode(self, value: Union[bytes, int]) -> Any:
"""Decode a value retrieved from Redis."""
...

def get_client(self, write: bool = False) -> Redis:
"""Get a Redis client instance for read or write operations."""
...
Loading