django-redis Documentation

Full featured redis cache backend for Django.

3,086 stars Python Python 1 file ยท ~16,938 tokens
RAW Doc

Docker & Self-Hosted Deployment Verified OCI

Deploy django-redis on any server, homelab, or cloud container platform.

1-Click Terminal Command
bash (docker run)
docker run -d --name django-redis -p 6379:6379 --restart always redis:alpine
Configured Services & Ports
โš™๏ธ redis
image: redis:alpine
๐Ÿ”Œ Ports: 6379:6379
โš™๏ธ redis-sentinel
image: redis:alpine
๐Ÿ”Œ Ports: 26379:26379
docker-compose.yml
yaml (docker-compose.yml)
services:
  redis:
    image: redis:alpine
    healthcheck:
      test: ['CMD', 'redis-cli', 'ping']
      start_period: 1m
      start_interval: 1s
    ports:
      - 6379:6379

  redis-sentinel:
    command:
      # Force `sh` as the shell as the multiline quoted string below is not
      # being written correctly, and it's not clear what shell is being run.
      - sh
      - -c
      # Generate a sentinel configuration that is writable by the sentinel
      - |
        echo '
        sentinel resolve-hostnames yes
        sentinel monitor redis redis 6379 1
        sentinel down-after-milliseconds redis 3200
        sentinel failover-timeout redis 10000
        sentinel parallel-syncs redis 1
        ' > /etc/redis-sentinel.conf

        exec redis-server /etc/redis-sentinel.conf --sentinel
    depends_on:
      redis:
        condition: service_healthy
    image: redis:alpine
    healthcheck:
      test: ['CMD', 'redis-cli', '-p', '26379', 'ping']
      start_period: 1m
      start_interval: 1s
    ports:
      - 26379:26379

File: README.rst

============================== Redis cache backend for Django

.. image:: https://jazzband.co/static/img/badge.svg
:target: https://jazzband.co/
:alt: Jazzband

.. image:: https://github.com/jazzband/django-redis/actions/workflows/ci.yml/badge.svg
:target: https://github.com/jazzband/django-redis/actions/workflows/ci.yml
:alt: GitHub Actions

.. image:: https://codecov.io/gh/jazzband/django-redis/branch/master/graph/badge.svg
:target: https://codecov.io/gh/jazzband/django-redis
:alt: Coverage

.. image:: https://img.shields.io/pypi/v/django-redis.svg?style=flat
:target: https://pypi.org/project/django-redis/

This is a Jazzband <https://jazzband.co>_ project. By contributing you agree
to abide by the Contributor Code of Conduct <https://jazzband.co/about/conduct>_ and follow the guidelines <https://jazzband.co/about/guidelines>_.

Introduction

django-redis is a BSD licensed, full featured Redis cache and session backend
for Django.

Why use django-redis?

text
- Uses native redis-py url notation connection strings
- Pluggable clients
- Pluggable parsers
- Pluggable serializers
- Primary/secondary support in the default client
- Comprehensive test suite
- Used in production in several projects as cache and session storage
- Supports infinite timeouts
- Facilities for raw access to Redis client/connection pool
- Highly configurable (can emulate memcached exception behavior, for example)
- Unix sockets supported by default

Requirements
~~~~~~~~~~~~

- `Python`_ 3.10+
- `Django`_ 5.2+
- `redis-py`_ 4.0.2+
- `Redis server`_ 2.8+

.. _Python: https://www.python.org/downloads/
.. _Django: https://www.djangoproject.com/download/
.. _redis-py: https://pypi.org/project/redis/
.. _Redis server: https://redis.io/download

User guide
----------

Installation
~~~~~~~~~~~~

Install with pip:

.. code-block:: console

    $ python -m pip install django-redis

Configure as cache backend

To start using django-redis, you should change your Django cache settings to
something like:

.. code-block:: python

text
CACHES = {
    "default": {
        "BACKEND": "django_redis.cache.RedisCache",
        "LOCATION": "redis://127.0.0.1:6379/1",
    }
}

django-redis uses the redis-py native URL notation for connection strings, it
allows better interoperability and has a connection string in more "standard"
way. Some examples:

  • redis://[[username]:[password]]@localhost:6379/0
  • rediss://[[username]:[password]]@localhost:6379/0
  • unix://[[username]:[password]]@/path/to/socket.sock?db=0

Three URL schemes are supported:

  • redis://: creates a normal TCP socket connection
  • rediss://: creates a SSL wrapped TCP socket connection
  • unix:// creates a Unix Domain Socket connection

There are several ways to specify a database number:

  • A db querystring option, e.g. redis://localhost?db=0
  • If using the redis:// scheme, the path argument of the URL, e.g.
    redis://localhost/0

When using Redis' ACLs <https://redis.io/topics/acl>_, you will need to add
the username and the password in the connection string or in OPTIONS with
the keys USERNAME and PASSWORD. NOTE: Values in the connection string
have precedence!

The login for the user django would look like this:

.. code-block:: python

text
CACHES = {
    "default": {
        "BACKEND": "django_redis.cache.RedisCache",
        "LOCATION": "redis://django:mysecret@localhost:6379/0",
    }
}

Instead you may specify both of these values in OPTIONS:

.. code-block:: python

text
CACHES = {
    "default": {
        "BACKEND": "django_redis.cache.RedisCache",
        "LOCATION": "redis://localhost:6379/0",
        "OPTIONS": {
            "USERNAME": "django",
            "PASSWORD": "mysecret",
        }
    }
}

And, finally you may mix the two as follows (be sure not to include a password,
even if blank in the connection string):

.. code-block:: python

text
CACHES = {
    "default": {
        "BACKEND": "django_redis.cache.RedisCache",
        "LOCATION": "redis://django@localhost:6379/0",
        "OPTIONS": {"PASSWORD": "mysecret"}
    }
}

Configure as session backend

text
Django can by default use any cache backend as session backend and you benefit
from that by using django-redis as backend for session storage without
installing any additional backends:

.. code-block:: python

    SESSION_ENGINE = "django.contrib.sessions.backends.cache"
    SESSION_CACHE_ALIAS = "default"

Testing with django-redis
~~~~~~~~~~~~~~~~~~~~~~~~~

django-redis supports customizing the underlying Redis client (see "Pluggable
clients"). This can be used for testing purposes.

In case you want to flush all data from the cache after a test, add the
following lines to your test class:

.. code-block:: python

    from django_redis import get_redis_connection

    def tearDown(self):
        get_redis_connection("default").flushall()

Advanced usage
--------------

Pickle version
~~~~~~~~~~~~~~

For almost all values, django-redis uses pickle to serialize objects.

The ``pickle.DEFAULT_PROTOCOL`` version of pickle is used by default to ensure safe upgrades and compatibility across Python versions.
If you want set a concrete version, you can do it, using ``PICKLE_VERSION`` option:

.. code-block:: python

    CACHES = {
        "default": {
            # ...
            "OPTIONS": {
                "PICKLE_VERSION": -1  # Will use highest protocol version available
            }
        }
    }

Socket timeout
~~~~~~~~~~~~~~

Socket timeout can be set using ``SOCKET_TIMEOUT`` and
``SOCKET_CONNECT_TIMEOUT`` options:

.. code-block:: python

    CACHES = {
        "default": {
            # ...
            "OPTIONS": {
                "SOCKET_CONNECT_TIMEOUT": 5,  # seconds
                "SOCKET_TIMEOUT": 5,  # seconds
            }
        }
    }

``SOCKET_CONNECT_TIMEOUT`` is the timeout for the connection to be established
and ``SOCKET_TIMEOUT`` is the timeout for read and write operations after the
connection is established.

Compression support
~~~~~~~~~~~~~~~~~~~

django-redis comes with compression support out of the box, but is deactivated
by default. You can activate it setting up a concrete backend:

.. code-block:: python

    CACHES = {
        "default": {
            # ...
            "OPTIONS": {
                "COMPRESSOR": "django_redis.compressors.zlib.ZlibCompressor",
            }
        }
    }

Let see an example, of how make it work with *lzma* compression format:

.. code-block:: python

    import lzma

    CACHES = {
        "default": {
            # ...
            "OPTIONS": {
                "COMPRESSOR": "django_redis.compressors.lzma.LzmaCompressor",
            }
        }
    }

*Lz4* compression support (requires the lz4 library):

.. code-block:: python

    import lz4

    CACHES = {
        "default": {
            # ...
            "OPTIONS": {
                "COMPRESSOR": "django_redis.compressors.lz4.Lz4Compressor",
            }
        }
    }

*Zstandard (zstd)* compression support (requires the pyzstd library):

.. code-block:: python

    import pyzstd

    CACHES = {
        "default": {
            # ...
            "OPTIONS": {
                "COMPRESSOR": "django_redis.compressors.zstd.ZStdCompressor",
            }
        }
    }

*Gzip* compression support:

.. code-block:: python

    import gzip

    CACHES = {
        "default": {
            # ...
            "OPTIONS": {
                "COMPRESSOR": "django_redis.compressors.gzip.GzipCompressor",
            }
        }
    }

Memcached exceptions behavior

In some situations, when Redis is only used for cache, you do not want
exceptions when Redis is down. This is default behavior in the memcached
backend and it can be emulated in django-redis.

For setup memcached like behaviour (ignore connection exceptions), you should
set IGNORE_EXCEPTIONS settings on your cache configuration:

.. code-block:: python

text
CACHES = {
    "default": {
        # ...
        "OPTIONS": {
            "IGNORE_EXCEPTIONS": True,
        }
    }
}

Also, you can apply the same settings to all configured caches, you can set the global flag in
your settings:

.. code-block:: python

text
DJANGO_REDIS_IGNORE_EXCEPTIONS = True

Log Ignored Exceptions

text
When ignoring exceptions with ``IGNORE_EXCEPTIONS`` or
``DJANGO_REDIS_IGNORE_EXCEPTIONS``, you may optionally log exceptions using the
global variable ``DJANGO_REDIS_LOG_IGNORED_EXCEPTIONS`` in your settings file::

    DJANGO_REDIS_LOG_IGNORED_EXCEPTIONS = True

If you wish to specify the logger in which the exceptions are output, simply
set the global variable ``DJANGO_REDIS_LOGGER`` to the string name and/or path
of the desired logger. This will default to ``__name__`` if no logger is
specified and ``DJANGO_REDIS_LOG_IGNORED_EXCEPTIONS`` is ``True``::

    DJANGO_REDIS_LOGGER = 'some.specified.logger'

Infinite timeout
~~~~~~~~~~~~~~~~

django-redis comes with infinite timeouts support out of the box. And it
behaves in same way as django backend contract specifies:

- ``timeout=0`` expires the value immediately.
- ``timeout=None`` infinite timeout

.. code-block:: python

    cache.set("key", "value", timeout=None)

Get ttl (time-to-live) from key

With Redis, you can access to ttl of any stored key, for it, django-redis
exposes ttl function.

It returns:

  • 0 if key does not exists (or already expired).
  • None for keys that exists but does not have any expiration.
  • ttl value for any volatile key (any key that has expiration).

.. code-block:: pycon

text
>>> from django.core.cache import cache
>>> cache.set("foo", "value", timeout=25)
>>> cache.ttl("foo")
25
>>> cache.ttl("not-existent")
0

With Redis, you can access to ttl of any stored key in milliseconds, for it, django-redis
exposes pttl function.

.. code-block:: pycon

text
>>> from django.core.cache import cache
>>> cache.set("foo", "value", timeout=25)
>>> cache.pttl("foo")
25000
>>> cache.pttl("not-existent")
0

Expire & Persist

text
Additionally to the simple ttl query, you can send persist a concrete key or
specify a new expiration timeout using the ``persist`` and ``expire`` methods:

.. code-block:: pycon

    >>> cache.set("foo", "bar", timeout=22)
    >>> cache.ttl("foo")
    22
    >>> cache.persist("foo")
    True
    >>> cache.ttl("foo")
    None

.. code-block:: pycon

    >>> cache.set("foo", "bar", timeout=22)
    >>> cache.expire("foo", timeout=5)
    True
    >>> cache.ttl("foo")
    5

The ``expire_at`` method can be used to make the key expire at a specific moment in time.

.. code-block:: pycon

    >>> cache.set("foo", "bar", timeout=22)
    >>> cache.expire_at("foo", datetime.now() + timedelta(hours=1))
    True
    >>> cache.ttl("foo")
    3600

The ``pexpire_at`` method can be used to make the key expire at a specific moment in time with milliseconds precision:

.. code-block:: pycon

    >>> cache.set("foo", "bar", timeout=22)
    >>> cache.pexpire_at("foo", datetime.now() + timedelta(milliseconds=900, hours=1))
    True
    >>> cache.ttl("foo")
    3601
    >>> cache.pttl("foo")
    3600900

The ``pexpire`` method can be used to provide millisecond precision:

.. code-block:: pycon

    >>> cache.set("foo", "bar", timeout=22)
    >>> cache.pexpire("foo", timeout=5500)
    True
    >>> cache.pttl("foo")
    5500

Locks
~~~~~

It also supports the Redis ability to create Redis distributed named locks. The
Lock interface is identical to the ``threading.Lock`` so you can use it as
replacement.

.. code-block:: python

    with cache.lock("somekey"):
        do_some_thing()

Scan & Delete keys in bulk

django-redis comes with some additional methods that help with searching or
deleting keys using glob patterns.

.. code-block:: pycon

text
>>> from django.core.cache import cache
>>> cache.keys("foo_*")
["foo_1", "foo_2"]

A simple search like this will return all matched values. In databases with a
large number of keys this isn't suitable method. Instead, you can use the
iter_keys function that works like the keys function but uses Redis
server side cursors. Calling iter_keys will return a generator that you can
then iterate over efficiently.

.. code-block:: pycon

text
>>> from django.core.cache import cache
>>> cache.iter_keys("foo_*")
<generator object algo at 0x7ffa9c2713a8>
>>> next(cache.iter_keys("foo_*"))
"foo_1"

For deleting keys, you should use delete_pattern which has the same glob
pattern syntax as the keys function and returns the number of deleted keys.

.. code-block:: pycon

text
>>> from django.core.cache import cache
>>> cache.delete_pattern("foo_*")

To achieve the best performance while deleting many keys, you should set DJANGO_REDIS_SCAN_ITERSIZE to a relatively
high number (e.g., 100_000) by default in Django settings or pass it directly to the delete_pattern.

.. code-block:: pycon

text
>>> from django.core.cache import cache
>>> cache.delete_pattern("foo_*", itersize=100_000)

Redis native commands

text
django-redis has limited support for some Redis atomic operations, such as the
commands ``SETNX`` and ``INCR``.

You can use the ``SETNX`` command through the backend ``set()`` method with the
``nx`` parameter:

.. code-block:: pycon

    >>> from django.core.cache import cache
    >>> cache.set("key", "value1", nx=True)
    True
    >>> cache.set("key", "value2", nx=True)
    False
    >>> cache.get("key")
    "value1"

Also, the ``incr`` and ``decr`` methods use Redis atomic operations when the
value that a key contains is suitable for it.

Raw client access
~~~~~~~~~~~~~~~~~

In some situations your application requires access to a raw Redis client to
use some advanced features that aren't exposed by the Django cache interface.
To avoid storing another setting for creating a raw connection, django-redis
exposes functions with which you can obtain a raw client reusing the cache
connection string: ``get_redis_connection(alias)``.

.. code-block:: pycon

    >>> from django_redis import get_redis_connection
    >>> con = get_redis_connection("default")
    >>> con
    <redis.client.Redis object at 0x2dc4510>

WARNING: Not all pluggable clients support this feature.

Connection pools
~~~~~~~~~~~~~~~~

Behind the scenes, django-redis uses the underlying redis-py connection pool
implementation, and exposes a simple way to configure it. Alternatively, you
can directly customize a connection/connection pool creation for a backend.

The default redis-py behavior is to not close connections, recycling them when
possible.

Configure default connection pool
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

The default connection pool is simple. For example, you can customize the
maximum number of connections in the pool by setting ``CONNECTION_POOL_KWARGS``
in the ``CACHES`` setting:

.. code-block:: python

    CACHES = {
        "default": {
            "BACKEND": "django_redis.cache.RedisCache",
            # ...
            "OPTIONS": {
                "CONNECTION_POOL_KWARGS": {"max_connections": 100}
            }
        }
    }

You can verify how many connections the pool has opened with the following
snippet:

.. code-block:: python

    from django_redis import get_redis_connection

    r = get_redis_connection("default")  # Use the name you have defined for Redis in settings.CACHES
    connection_pool = r.connection_pool
    print("Created connections so far: %d" % connection_pool._created_connections)

Since the default connection pool passes all keyword arguments it doesn't use
to its connections, you can also customize the connections that the pool makes
by adding those options to ``CONNECTION_POOL_KWARGS``:

.. code-block:: python

    CACHES = {
        "default": {
            # ...
            "OPTIONS": {
                "CONNECTION_POOL_KWARGS": {"max_connections": 100, "retry_on_timeout": True}
            }
        }
    }

Use your own connection pool subclass
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Sometimes you want to use your own subclass of the connection pool. This is
possible with django-redis using the ``CONNECTION_POOL_CLASS`` parameter in the
backend options.

.. code-block:: python

    from redis.connection import ConnectionPool

    class MyOwnPool(ConnectionPool):
        # Just doing nothing, only for example purpose
        pass

.. code-block:: python

    # Omitting all backend declaration boilerplate code.

    "OPTIONS": {
        "CONNECTION_POOL_CLASS": "myproj.mypool.MyOwnPool",
    }

Customize connection factory
^^^^^^^^^^^^^^^^^^^^^^^^^^^^

If none of the previous methods satisfies you, you can get in the middle of the
django-redis connection factory process and customize or completely rewrite it.

By default, django-redis creates connections through the
``django_redis.pool.ConnectionFactory`` class that is specified in the global
Django setting ``DJANGO_REDIS_CONNECTION_FACTORY``.

.. code-block:: python

    class ConnectionFactory(object):
        def get_connection_pool(self, params: dict):
            # Given connection parameters in the `params` argument, return new
            # connection pool. It should be overwritten if you want do
            # something before/after creating the connection pool, or return
            # your own connection pool.
            pass

        def get_connection(self, params: dict):
            # Given connection parameters in the `params` argument, return a
            # new connection. It should be overwritten if you want to do
            # something before/after creating a new connection. The default
            # implementation uses `get_connection_pool` to obtain a pool and
            # create a new connection in the newly obtained pool.
            pass

        def get_or_create_connection_pool(self, params: dict):
            # This is a high layer on top of `get_connection_pool` for
            # implementing a cache of created connection pools. It should be
            # overwritten if you want change the default behavior.
            pass

        def make_connection_params(self, url: str) -> dict:
            # The responsibility of this method is to convert basic connection
            # parameters and other settings to fully connection pool ready
            # connection parameters.
            pass

        def connect(self, url: str):
            # This is really a public API and entry point for this factory
            # class. This encapsulates the main logic of creating the
            # previously mentioned `params` using `make_connection_params` and
            # creating a new connection using the `get_connection` method.
            pass

Use the sentinel connection factory
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

In order to facilitate using `Redis Sentinels`_, django-redis comes with a
built in sentinel connection factory, which creates sentinel connection pools.
In order to enable this functionality you should add the following:


.. code-block:: python

    # Enable the alternate connection factory.
    DJANGO_REDIS_CONNECTION_FACTORY = 'django_redis.pool.SentinelConnectionFactory'

    # These sentinels are shared between all the examples, and are passed
    # directly to redis Sentinel. These can also be defined inline.
    SENTINELS = [
        ('sentinel-1', 26379),
        ('sentinel-2', 26379),
        ('sentinel-3', 26379),
    ]

    CACHES = {
        "default": {
            "BACKEND": "django_redis.cache.RedisCache",
            # The hostname in LOCATION is the primary (service / master) name
            "LOCATION": "redis://service_name/db",
            "OPTIONS": {
                # While the default client will work, this will check you
                # have configured things correctly, and also create a
                # primary and replica pool for the service specified by
                # LOCATION rather than requiring two URLs.
                "CLIENT_CLASS": "django_redis.client.SentinelClient",

                # Sentinels which are passed directly to redis Sentinel.
                "SENTINELS": SENTINELS,

                # kwargs for redis Sentinel (optional). Example with auth on sentinels
                "SENTINEL_KWARGS": {
                    "username": "sentinel-user",
                    "password": "sentinel-pass",
                },

                # You can still override the connection pool (optional).
                "CONNECTION_POOL_CLASS": "redis.sentinel.SentinelConnectionPool",
            },
        },

        # A minimal example using the SentinelClient.
        "minimal": {
            "BACKEND": "django_redis.cache.RedisCache",

            # The SentinelClient will use this location for both the primaries
            # and replicas.
            "LOCATION": "redis://minimal_service_name/db",

            "OPTIONS": {
                "CLIENT_CLASS": "django_redis.client.SentinelClient",
                "SENTINELS": SENTINELS,
            },
        },

        # A minimal example using the DefaultClient.
        "other": {
            "BACKEND": "django_redis.cache.RedisCache",
            "LOCATION": [
                # The DefaultClient is [primary, replicas...], but with the
                # SentinelConnectionPool it only requires one "is_master=0".
                "redis://other_service_name/db?is_master=1",
                "redis://other_service_name/db?is_master=0",
            ],
            "OPTIONS": {"SENTINELS": SENTINELS},
        },

        # A minimal example only using only replicas in read only mode (and
        # the DefaultClient).
        "readonly": {
            "BACKEND": "django_redis.cache.RedisCache",
            "LOCATION": "redis://readonly_service_name/db?is_master=0",
            "OPTIONS": {"SENTINELS": SENTINELS},
        },
    }

It is also possible to set some caches as sentinels and some as not:

.. code-block:: python

    SENTINELS = [
        ('sentinel-1', 26379),
        ('sentinel-2', 26379),
        ('sentinel-3', 26379),
    ]
    CACHES = {
        "sentinel": {
            "BACKEND": "django_redis.cache.RedisCache",
            "LOCATION": "redis://service_name/db",
            "OPTIONS": {
                "CLIENT_CLASS": "django_redis.client.SentinelClient",
                "SENTINELS": SENTINELS,
                "CONNECTION_POOL_CLASS": "redis.sentinel.SentinelConnectionPool",
                "CONNECTION_FACTORY": "django_redis.pool.SentinelConnectionFactory",
            },
        },
        "default": {
            "BACKEND": "django_redis.cache.RedisCache",
            "LOCATION": "redis://127.0.0.1:6379/1",
            "OPTIONS": {
                "CLIENT_CLASS": "django_redis.client.DefaultClient",
            },
        },
    }

.. _Redis Sentinels: https://redis.io/topics/sentinel

Pluggable parsers
~~~~~~~~~~~~~~~~~

`redis-py`_, the Python Redis client used by django-redis, will automatically
use a C-based parser if the `hiredis`_ package is installed in your environment.
This can provide a significant performance boost for parsing Redis replies.

To take advantage of this, simply install the `hiredis` package with pip:

.. code-block:: console

    $ python -m pip install hiredis

No additional configuration in your Django settings is required. django-redis
will use the faster parser automatically.

.. _hiredis: https://pypi.org/project/hiredis/

Pluggable clients
~~~~~~~~~~~~~~~~~

django-redis is designed for to be very flexible and very configurable. For it,
it exposes a pluggable backends that make easy extend the default behavior, and
it comes with few ones out the box.

Default client
^^^^^^^^^^^^^^

Almost all about the default client is explained, with one exception: the
default client comes with replication support.

To connect to a Redis replication setup, you should change the ``LOCATION`` to
something like:

.. code-block:: python

    "LOCATION": [
        "redis://127.0.0.1:6379/1",
        "redis://127.0.0.1:6378/1",
    ]

The first connection string represents the primary server and the rest to
replica servers.

WARNING: Replication setup is not heavily tested in production environments.

Shard client
^^^^^^^^^^^^

This pluggable client implements client-side sharding. It inherits almost all
functionality from the default client. To use it, change your cache settings to
something like this:

.. code-block:: python

    CACHES = {
        "default": {
            "BACKEND": "django_redis.cache.RedisCache",
            "LOCATION": [
                "redis://127.0.0.1:6379/1",
                "redis://127.0.0.1:6379/2",
            ],
            "OPTIONS": {
                "CLIENT_CLASS": "django_redis.client.ShardClient",
            }
        }
    }

WARNING: Shard client is still experimental, so be careful when using it in
production environments.

Herd client
^^^^^^^^^^^

This pluggable client helps dealing with the thundering herd problem. You can read more about it
on link: `Wikipedia <https://en.wikipedia.org/wiki/Thundering_herd_problem>`_

Like previous pluggable clients, it inherits all functionality from the default client, adding some
additional methods for getting/setting keys.

.. code-block:: python

    CACHES = {
        "default": {
            "BACKEND": "django_redis.cache.RedisCache",
            "LOCATION": "redis://127.0.0.1:6379/1",
            "OPTIONS": {
                "CLIENT_CLASS": "django_redis.client.HerdClient",
            }
        }
    }

This client exposes additional settings:

- ``CACHE_HERD_TIMEOUT``: Set default herd timeout. (Default value: 60s)

Pluggable serializer
~~~~~~~~~~~~~~~~~~~~

The pluggable clients serialize data before sending it to the server. By
default, django-redis serializes the data using the Python ``pickle`` module.
This is very flexible and can handle a large range of object types.

To serialize using JSON instead, the serializer ``JSONSerializer`` is also
available.

.. code-block:: python

    CACHES = {
        "default": {
            "BACKEND": "django_redis.cache.RedisCache",
            "LOCATION": "redis://127.0.0.1:6379/1",
            "OPTIONS": {
                "CLIENT_CLASS": "django_redis.client.DefaultClient",
                "SERIALIZER": "django_redis.serializers.json.JSONSerializer",
            }
        }
    }

There's also support for serialization using `MsgPack`_ (that requires the
msgpack library):

.. code-block:: python

    CACHES = {
        "default": {
            "BACKEND": "django_redis.cache.RedisCache",
            "LOCATION": "redis://127.0.0.1:6379/1",
            "OPTIONS": {
                "CLIENT_CLASS": "django_redis.client.DefaultClient",
                "SERIALIZER": "django_redis.serializers.msgpack.MSGPackSerializer",
            }
        }
    }

.. _MsgPack: https://msgpack.org/

Pluggable Redis client

django-redis uses the Redis client redis.client.StrictClient by default. It
is possible to use an alternative client.

You can customize the client used by setting REDIS_CLIENT_CLASS in the
CACHES setting. Optionally, you can provide arguments to this class by
setting REDIS_CLIENT_KWARGS.

.. code-block:: python

text
CACHES = {
    "default": {
        "OPTIONS": {
            "REDIS_CLIENT_CLASS": "my.module.ClientClass",
            "REDIS_CLIENT_KWARGS": {"some_setting": True},
        }
    }
}

Closing Connections

text
The default django-redis behavior on close() is to keep the connections to Redis server.

You can change this default behaviour for all caches by the ``DJANGO_REDIS_CLOSE_CONNECTION = True``
in the django settings (globally) or (at cache level) by setting ``CLOSE_CONNECTION: True`` in the ``OPTIONS``
for each configured cache.

Setting True as a value will instruct the django-redis to close all the connections (since v. 4.12.2), irrespectively of its current usage.

.. code-block:: python

    CACHES = {
        "default": {
            "BACKEND": "django_redis.cache.RedisCache",
            "LOCATION": "redis://127.0.0.1:6379/1",
            "OPTIONS": {
                "CLIENT_CLASS": "django_redis.client.DefaultClient",
                "CLOSE_CONNECTION": True,
            }
        }
    }

SSL/TLS and Self-Signed certificates

In case you encounter a Redis server offering a TLS connection using a
self-signed certificate you may disable certification verification with the
following:

.. code-block:: python

text
CACHES = {
    "default": {
        "BACKEND": "django_redis.cache.RedisCache",
        "LOCATION": "rediss://127.0.0.1:6379/1",
        "OPTIONS": {
            "CLIENT_CLASS": "django_redis.client.DefaultClient",
            "CONNECTION_POOL_KWARGS": {"ssl_cert_reqs": None}
        }
    }
}

License

.. code-block:: text

text
Copyright (c) 2011-2015 Andrey Antukh <[email protected]>
Copyright (c) 2011 Sean Bleier

All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
   notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
   notice, this list of conditions and the following disclaimer in the
   documentation and/or other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products
   derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS`` AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

File: AUTHORS.rst

Andrei Antoukh / niwibe https://github.com/niwibe
Sean Bleier https://github.com/sebleier
Matt Dennewitz https://github.com/blackbrrr
Jannis Leidel https://github.com/jezdez
S. Angel / Twidi https://github.com/twidi
Noah Kantrowitz / coderanger https://github.com/coderanger
Martin Mahner / bartTC https://github.com/bartTC
Timothรฉe Peignier / cyberdelia https://github.com/cyberdelia
Lior Sion / liorsion https://github.com/liorsion
Ales Zoulek / aleszoulek https://github.com/aleszoulek
James Aylett / jaylett https://github.com/jaylett
Todd Boland / boland https://github.com/boland
David Zderic / dzderic https://github.com/dzderic
Kirill Zaitsev / teferi https://github.com/teferi
Jon Dufresne https://github.com/jdufresne
Anรจs Foufa https://github.com/AnesFoufa
Segyo Myung https://github.com/myungsegyo


File: CHANGELOG.rst

Changelog

.. towncrier release notes start

django-redis 7.0.0 (2026-06-02)

Features

  • Added the ability to pass redis username in the cache options (#657 <https://github.com/jazzband/django-redis/issues/657>_)
  • RedisCache does not attempt to close clients which have not been initialized. (#796 <https://github.com/jazzband/django-redis/issues/796>_)
  • Add sorted set operations (zadd, zrange, zrem, etc.) and mixins for RedisCache (#797 <https://github.com/jazzband/django-redis/issues/797>_)
  • Centralize configuration in pyproject.toml, drop EoL Python & Django
    versions, and add support & testing for modern Python & Django versions. (#820 <https://github.com/jazzband/django-redis/issues/820>_)
  • Provide TypeVar defaults & provide initial typing for RedisCache. (#829 <https://github.com/jazzband/django-redis/issues/829>_)

Bug Fixes

  • Fix IntEnum encoding (#602 <https://github.com/jazzband/django-redis/issues/602>_)
  • Fix incorrect Redis typing that relied on the legacy types-redis package, and update the public API to avoid exposing redis-py key types (the encode/decode/make_key methods allow a different API surface). (#822 <https://github.com/jazzband/django-redis/issues/822>_)

Miscellaneous

  • Drop support for Django 5.0 (EOL) (#779 <https://github.com/jazzband/django-redis/issues/779>_)
  • Clean & organize ruff config (#781 <https://github.com/jazzband/django-redis/issues/781>_)
  • Replace black with ruff format (#782 <https://github.com/jazzband/django-redis/issues/782>_)
  • Update RedisCache.close to not forward kwargs to the client implementation. (#788 <https://github.com/jazzband/django-redis/issues/788>_)
  • Rename 'name' parameter to 'key' in all sorted set methods for better consistency with Redis terminology (#811 <https://github.com/jazzband/django-redis/issues/811>_)
  • Fix hash method parameters: rename 'name' โ†’ 'key', 'key' โ†’ 'field' to align with Redis/Valkey terminology. Add version parameter to hlen() and hkeys(). Fix make_key() to only apply to hash key, not fields. (#812 <https://github.com/jazzband/django-redis/issues/812>_)
  • pre-commit autoupdate (#819 <https://github.com/jazzband/django-redis/issues/819>_)
  • Use from __future__ import annotations to postpone evaluation of annotations. (#823 <https://github.com/jazzband/django-redis/issues/823>_)
  • Increase mypy strictness, fix typing configuration, and fix type errors. (#824 <https://github.com/jazzband/django-redis/issues/824>_)
  • This change updates the compose configuration, and moves it to tests
    directory as it is only for testing. (#825 <https://github.com/jazzband/django-redis/issues/825>_)
  • Remove code handling unsupported Django versions (#826 <https://github.com/jazzband/django-redis/issues/826>_)
  • Increase mypy type coverage & update strictness overrides to only target specific modules (#827 <https://github.com/jazzband/django-redis/issues/827>_)

django-redis 6.0.0 (2025-06-17)

Features

  • Support HashMaps (#598 <https://github.com/jazzband/django-redis/issues/598>_)
  • Support gzip compression (#688 <https://github.com/jazzband/django-redis/issues/688>_)
  • Support for sets and support basic operations, sadd, scard, sdiff, sdiffstore, sinter, sinterstore, smismember, sismember, smembers, smove, spop, srandmember, srem, sscan, sscan_iter, sunion, sunionstore (#730 <https://github.com/jazzband/django-redis/issues/730>_)

Bug Fixes

  • Hotfix for timeout=DEFAULT_TIMEOUT in expire and pexpire (#724 <https://github.com/jazzband/django-redis/issues/724>_)
  • Fix is_master parsing error for write separation in sentinel mode (#749 <https://github.com/jazzband/django-redis/issues/749>_)
  • Added blocking parameter for cache.lock (#752 <https://github.com/jazzband/django-redis/issues/752>_)

Miscellaneous

  • Added support for Python 3.12 (#689 <https://github.com/jazzband/django-redis/issues/689>_)
  • Pin pytest to <7.0 until compatibility issues are resolved (#690 <https://github.com/jazzband/django-redis/issues/690>_)
  • Replace isort and flake8 with ruff (#692 <https://github.com/jazzband/django-redis/issues/692>_)
  • Drop django 4.0 (#693 <https://github.com/jazzband/django-redis/issues/693>_)
  • Upgrade black to 23.10.1 (#695 <https://github.com/jazzband/django-redis/issues/695>_)
  • Typed DefaultClient (#696 <https://github.com/jazzband/django-redis/issues/696>_)
  • Support pytest>=7 (#697 <https://github.com/jazzband/django-redis/issues/697>_)
  • Drop support for django 3.2, python 3.6 and python 3.7 (#699 <https://github.com/jazzband/django-redis/issues/699>_)
  • Support tox 4 (#701 <https://github.com/jazzband/django-redis/issues/701>_)
  • Configured dependabot for github actions (#702 <https://github.com/jazzband/django-redis/issues/702>_)
  • Use ubuntu-latest for CI (#703 <https://github.com/jazzband/django-redis/issues/703>_)
  • Dropped support for django 4.1 and added support for django 5.0 (#729 <https://github.com/jazzband/django-redis/issues/729>_)
  • Added support for django 5.1 (#754 <https://github.com/jazzband/django-redis/issues/754>_)
  • Update minimum supported versions in README.md: Python to 3.8, Django to 4.2, redis-py to 4.0.2 (#755 <https://github.com/jazzband/django-redis/issues/755>_)
  • Added support for Python 3.13 (#756 <https://github.com/jazzband/django-redis/issues/756>_)
  • Speed up tests by using pytest-xdist and separating settings on different redis databases.
    Dropped pytest-django
    Using docker-compose for setting up redis containers for testing
    Use tox-uv (#757 <https://github.com/jazzband/django-redis/issues/757>_)
  • Confirm support for Django 5.2.
    Fix shadowing builtin Python exceptions. (#824 <https://github.com/jazzband/django-redis/issues/824>_)

Deprecations and Removals

  • Drop support for Python 3.8 (#852 <https://github.com/jazzband/django-redis/issues/852>_)

django-redis 5.4.0 (2023-10-01)

Features

  • Connection factory goes to cache options (#680 <https://github.com/jazzband/django-redis/issues/680>_)

Documentation

  • Added note in docs for correctly configuring hiredis parser when using redis-py version 5. (#677 <https://github.com/jazzband/django-redis/issues/677>_)

django-redis 5.3.0 (2023-06-16)

Features

  • Add support for django 4 (#627 <https://github.com/jazzband/django-redis/issues/627>_)

Bug Fixes

  • Access django_redis.cache.DJANGO_REDIS_SCAN_ITERSIZE and django_redis.client.herd.CACHE_HERD_TIMEOUT in runtime to not read Django settings in import time. (#638 <https://github.com/jazzband/django-redis/issues/638>_)
  • Skipping pickle serializer test for django >= 4.2 (#646 <https://github.com/jazzband/django-redis/issues/646>_)

Miscellaneous

  • Speed up deleting multiple keys by a pattern with pipelines and larger itersize (#609 <https://github.com/jazzband/django-redis/issues/609>_)
  • Print full exception traceback when logging ignored exceptions (#611 <https://github.com/jazzband/django-redis/issues/611>_)
  • Fix mypy linting (#626 <https://github.com/jazzband/django-redis/issues/626>_)
  • Added support for python 3.11 (#633 <https://github.com/jazzband/django-redis/issues/633>_)
  • Fix CI, running tox<4 to still support Python 3.6. (#645 <https://github.com/jazzband/django-redis/issues/645>_)
  • Dropped support for django 2.2 and 3.1 (#649 <https://github.com/jazzband/django-redis/issues/649>_)
  • Run actions & tox against Django 4..2 (#668 <https://github.com/jazzband/django-redis/issues/668>_)

django-redis 5.2.0 (2021-12-22)

Bug Fixes

  • Block use with broken redis-py 4.0.0 and 4.0.1 (#542 <https://github.com/jazzband/django-redis/issues/542>_)

Miscellaneous

  • Unblock redis-py >=4.0.2 (#576 <https://github.com/jazzband/django-redis/issues/576>_)
  • Add support for django 4 (#579 <https://github.com/jazzband/django-redis/issues/579>_)

Django_Redis 5.1.0 (2021-11-29)

Features

  • Add Python 3.10 to CI (#536 <https://github.com/jazzband/django-redis/issues/536>_)
  • Configured towncrier to generate the changelog. (#548 <https://github.com/jazzband/django-redis/issues/548>_)
  • Added django_redis.compressors.zstd.ZStdCompressor to provide pyzstd cache value compression. (#551 <https://github.com/jazzband/django-redis/issues/551>_)
  • Change pickle default version to Python default instead of highest version. (#555 <https://github.com/jazzband/django-redis/issues/555>_)
  • Add hiredis extra dependency to request redis[hiredis]. (#556 <https://github.com/jazzband/django-redis/issues/556>_)
  • Add pexpireat to allow setting 'expire at' with millisecond precision. (#564 <https://github.com/jazzband/django-redis/issues/564>_)

Bug Fixes

  • Make expire, pexpire, expireat and persist return the redis client value (#564 <https://github.com/jazzband/django-redis/issues/564>_)

Miscellaneous

  • Convert most unittest class tests to pytest tests. (#553 <https://github.com/jazzband/django-redis/issues/553>_)
  • Update type comments to type annotations. (#568 <https://github.com/jazzband/django-redis/issues/568>_)
  • Pin redis-py to 3.x until 4.x breaking changes can be addressed. (#570 <https://github.com/jazzband/django-redis/issues/570>_)

Documentation

  • Clarify redis primary name in sentinel documentation. (#529 <https://github.com/jazzband/django-redis/issues/529>_)
  • Add documentation on configuring self signed SSL certificates. (#559 <https://github.com/jazzband/django-redis/issues/559>_)

django-redis 5.0.0 (2021-05-30)

  • supporting django 3.1 and django 3.2
  • dropped support for python 3.5
  • added support for python 3.9
  • started type hinting the codebase
  • ensure connections are closed
  • fixed ShardClient .clear() method
  • .delete() now returns boolean from django 3.1 onwards
  • disconnect connection pools on .close()
  • added support for redis sentinel
  • added .expire_at() method
  • fixed .incr() when ttl is None or when the number is larger than 64 bit
  • fixed .incr_version() when ttl is None
  • added .pttl() method to the clients to support milli-second precision for
    ttl of a key
  • added .pexpire() method to the clients to support milli-second precision
    for setting expiry of a key

django-redis 4.12.1 (2020-05-27)

  • No code changes.
  • Fixed a typo in setup.cfg metadata preventing a successful release.

django-redis 4.12.0 (2020-05-27)

  • The project has moved to Jazzband <https://jazzband.co/>. This is the
    first release under the new organization. The new repository URL is
    <https://github.com/jazzband/django-redis>
    .
  • Removed support for end-of-life Django < 2.2.
  • Removed support for unmaintained redis-py 2.X.
  • Changed uses of deprecated smart_text() to smart_str().
  • Fixed deprecation warning with the msgpack serializer.
  • The .touch() method now uses the default timeout, to cache forever pass
    None.
  • Subclasses of JSONSerializer can now override the encoder_class
    attribute to change the JSON encoder. It defaults to DjangoJSONEncoder.
  • Fixed DefaultClient.set() to work with empty Pipeline.
  • The thread_local parameter is now forwarded to the Redis client.

django-redis 4.11.0 (2019-12-13)

  • Removed support for Python 2.7 and 3.4.
  • Removed support for Django 2.0 and 2.1.
  • Added support for Python 3.8.
  • Added support for Django 2.2 and 3.0.
  • Changed msgpack-python soft dependency to msgpack.
  • Fixed .touch() method for sharded client.
  • Fixed prefix escaping for the sharded client.
  • Fixed .add() method to return a bool.

django-redis 4.10.0 (2018-10-19)

  • Add support and testing for Django 2.1 and Python 3.7. No actual code changes
    were required.
  • Add support for redis-py 3.0.
  • Add touch command.

django-redis 4.9.1 (2018-10-19)

  • Pin redis version to 2.10.6

django-redis 4.9.0 (2018-03-01)

  • Add testing and support for Django 2.0. No actual code changes were required.
  • Escape KEY_PREFIX and VERSION when used in glob expressions.
  • Improve handling timeouts less than 1ms.
  • Remove fakeredis support.
  • Add datetime, date, time, and timedelta serialization support to the JSON
    serializer.
  • The deprecated feature of passing True as a timeout value is no longer
    supported.
  • Fix add() with a negative timeout to not store key (it is immediately
    invalid).
  • Remove support for Django < 1.11.
  • Add support for atomic incr if key is not set.

django-redis 4.8.0 (2017-04-25)

  • Drop deprecated exception with typo ConnectionInterrumped. Use
    ConnectionInterrupted instead.
  • Remove many workarounds related to old and not supported versions
    of django and redis-py.
  • Code cleaning and flake8 compliance fixes.
  • Add better impl for close method.
  • Fix compatibility warnings with python 3.6

django-redis 4.7.0 (2017-01-02)

  • Add the ability to enable write to replica servers when the primary server is
    not available.
  • Add itersize parameter to delete_pattern.

django-redis 4.6.0 (2016-11-02)

  • Fix incorrect behavior of clear() method.

django-redis 4.5.0 (2016-09-21)

  • Now only support Django 1.8 and above. Support for older versions has been dropped.
  • Remove undocumented and deprecated support for old connection string format.
  • Add support for PASSWORD option (useful when the password contains url unsafe
    characters).
  • Make the package compatible with fake redis.
  • Fix compatibility issues with latest django version (1.10).

django-redis 4.4.4 (2016-07-25)

  • Fix possible race condition on incr implementation using
    lua script (thanks to @prokaktus).

django-redis 4.4.3 (2016-05-17)

  • Fix minor ttl inconsistencies.

django-redis 4.4.2 (2016-04-21)

  • Fix timeout bug (thanks to @skorokithakis)

django-redis 4.4.1 (2016-04-13)

  • Add additional check for avoid wrong exception on get_redis_connection.

django-redis 4.4.0 (2016-04-12)

  • Make redis client pluggable (thanks to @arnuschky)
  • Add version number inside python module (thanks to @BertrandBordage)
  • Fix clear method (thanks to @ostcar)
  • Add the ability to specify key prefix on delete and delete_pattern.
  • BREAKING CHANGE: improved compression support (make it more plugable).

django-redis 4.3.0 (2015-10-31)

  • Improved exception handling in herd client (thanks to @brandoshmando)
  • Fix bug that not allows use generators on delete_many (thanks to @ostcar).
  • Remove obsolete code that makes hard dependency to mspack.

django-redis 4.2.0 (2015-07-03)

  • Add persist and expire methods.
  • Remove old and broken dummy client.
  • Expose a redis lock method.

django-redis 4.1.0 (2015-06-15)

  • Add plugable serializers architecture (thanks to @jdufresne)
  • Add json serializer (thanks to @jdufresne)
  • Add msgpack serializer (thanks to @uditagarwal)
  • Implement delete_pattern using iter_scan for better performance (thanks to @lenzenmi)

django-redis 4.0.0

  • Remove usage of deprecated get_cache method.
  • Added connection option SOCKET_CONNECT_TIMEOUT. [Jorge C. Leitรฃo].
  • Replace setex and friends with set, because it now supports all need for atomic.
    updates (thanks to @23doors) (re revert changes from 3.8.x branch).
  • Fix django 1.8 compatibilities.
  • Fix django 1.9 compatibilities.
  • BREAKING CHANGE: Now timeout=0 works as django specified (expires immediately)
  • Now requires redis server >= 2.8
  • BREAKING CHANGE: redis_cache is no longer a valid package name

django-redis 3.8.4

  • Backport django 1.8 fixes from master.

django-redis 3.8.3

  • Minor fix on regular expression for old url notation.

django-redis 3.8.2

  • Revert some changes from 3.8.1 that are incompatible with redis server < 2.6.12

django-redis 3.8.1

  • Fix documentation related to new url format.
  • Fix documentation parts that uses now removed functions.
  • Fix invalid url transformation from old format (password was not set properly)
  • Replace setex and friends with set, because it now supports all need for atomic
    updates (thanks to @23doors).

django-redis 3.8.0

  • Add compression support. (Thanks to @alanjds)
  • Change package name from redis_cache to django_redis.
  • Add backward compatibility layer for redis_cache package name.
  • BACKWARD INCOMPATIBLE CHANGE: use StrictRedis instead of Redis class of redis-py
  • Add redis dummy backend for development purposes. (Thanks to @papaloizouc)
  • Now use redis native url notation for connection string (the own connection string
    notation is also supported but is marked as deprecated).
  • Now requires redis-py >= 2.10.0
  • Remove deprecated raw_cache property from backend.

django-redis 3.7.2

  • Add missing forward of version parameter from add() to set() function. (by @fellowshipofone)

django-redis 3.7.1

  • Improve docs (by @dkingman).
  • Fix missing imports on sentinel client (by @opapy).
  • Connection closing improvements on sentinel client (by @opapy).

django-redis 3.7.0

  • Add support for django's KEY_FUNCTION and REVERSE_KEY_FUNCTION (by @teferi)
  • Accept float value for socket timeout.
  • Fix wrong behavior of DJANGO_REDIS_IGNORE_EXCEPTIONS with socket timeouts.
  • Backward incompatible change: now raises original exceptions instead of self defined.

django-redis 3.6.2

  • Add ttl method purposed to be included in django core.
  • Add iter_keys method that uses redis scan methods for memory efficient keys retrieval.
  • Add version keyword parameter to keys.
  • Deprecate django 1.3.x support.

django-redis 3.6.1

  • Fix wrong import on sentinel client.

django-redis 3.6.0

  • Add pluggable connection factory.
  • Negative timeouts now works as expected.
  • Delete operation now returns a number of deleted items instead of None.

django-redis 3.5.1

  • Fixed redis-py < 2.9.0 incompatibilities
  • Fixed runtests error with django 1.7

django-redis 3.5.0

  • Removed: stats module (should be replaced with an other in future)
  • New: experimental client for add support to redis-sentinel.
  • Now uses a django DEFAULT_TIMEOUT constant instead of True.
    Deprecation warning added for code that now uses True (unlikely).
  • Fix wrong forward of timeout on shard client.
  • Fix incr_version wrong behavior when using shard client (wrong client used for set new key).

django-redis 3.4.0

  • Fix exception name from ConnectionInterrumped to
    ConnectionInterrupted maintaining an old exception class
    for backward compatibility (thanks ลukasz Langa (@ambv))

  • Fix wrong behavior for "default" parameter on get method
    when DJANGO_REDIS_IGNORE_EXCEPTIONS is True
    (also thanks to ลukasz Langa (@ambv)).

  • Now added support for replication setups to default client (it still
    experimental because is not tested in production environments).

  • Merged SimpleFailoverClient experimental client (only for
    experiment with it, not ready for use in production)

  • Django 1.6 cache changes compatibility. Explicitly passing in
    timeout=None no longer results in using the default timeout.

  • Major code cleaning. (Thanks to Bertrand Bordage @BertrandBordage)

  • Bugfixes related to some index error on hashring module.

django-redis 3.3.0

  • Add SOCKET_TIMEOUT attribute to OPTIONS (thanks to @eclipticplane)

django-redis 3.2.0

  • Changed default behavior of connection error exceptions: now by default
    raises exception on connection error is occurred.

Thanks to Mรผmin ร–ztรผrk:

  • cache.add now uses setnx redis command (atomic operation)
  • cache.incr and cache.decr now uses redis incrby command (atomic operation)

django-redis 3.1.7

  • Fix python3 compatibility on utils module.

django-redis 3.1.6

  • Add nx argument on set method for both clients (thanks to Kirill Zaitsev)

django-redis 3.1.5

  • Bug fixes on sharded client.

django-redis 3.1.4

  • Now reuse connection pool on massive use of get_cache method.

django-redis 3.1.3

  • Fixed python 2.6 compatibility.

django-redis 3.1.2

  • Now on call close() not disconnect all connection pool.

django-redis 3.1.1

  • Fixed incorrect exception message on LOCATION has wrong format.
    (Thanks to Yoav Weiss)

django-redis 3.1

  • Helpers for access to raw redis connection.

django-redis 3.0

  • Python 3.2+ support.
  • Code cleaning and refactor.
  • Ignore exceptions (same behavior as memcached backend)
  • Pluggable clients.
  • Unified connection string.

django-redis 2.2.2

  • Bug fixes on keys and delete_pattern methods.

django-redis 2.2.1

  • Remove duplicate check if key exists on incr method.
  • Fix incorrect behavior of delete_pattern with sharded client.

django-redis 2.2

  • New delete_pattern method. Useful for delete keys using wildcard syntax.

django-redis 2.1

  • Many bug fixes.
  • Client side sharding.

File: CODE_OF_CONDUCT.md

Code of Conduct

As contributors and maintainers of the Jazzband projects, and in the interest of
fostering an open and welcoming community, we pledge to respect all people who
contribute through reporting issues, posting feature requests, updating documentation,
submitting pull requests or patches, and other activities.

We are committed to making participation in the Jazzband a harassment-free experience
for everyone, regardless of the level of experience, gender, gender identity and
expression, sexual orientation, disability, personal appearance, body size, race,
ethnicity, age, religion, or nationality.

Examples of unacceptable behavior by participants include:

  • The use of sexualized language or imagery
  • Personal attacks
  • Trolling or insulting/derogatory comments
  • Public or private harassment
  • Publishing other's private information, such as physical or electronic addresses,
    without explicit permission
  • Other unethical or unprofessional conduct

The Jazzband roadies have the right and responsibility to remove, edit, or reject
comments, commits, code, wiki edits, issues, and other contributions that are not
aligned to this Code of Conduct, or to ban temporarily or permanently any contributor
for other behaviors that they deem inappropriate, threatening, offensive, or harmful.

By adopting this Code of Conduct, the roadies commit themselves to fairly and
consistently applying these principles to every aspect of managing the jazzband
projects. Roadies who do not follow or enforce the Code of Conduct may be permanently
removed from the Jazzband roadies.

This code of conduct applies both within project spaces and in public spaces when an
individual is representing the project or its community.

Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by
contacting the roadies at [email protected]. All complaints will be reviewed and
investigated and will result in a response that is deemed necessary and appropriate to
the circumstances. Roadies are obligated to maintain confidentiality with regard to the
reporter of an incident.

This Code of Conduct is adapted from the Contributor Covenant, version
1.3.0, available at https://contributor-covenant.org/version/1/3/0/


File: CONTRIBUTING.rst

.. image:: https://jazzband.co/static/img/jazzband.svg
:target: https://jazzband.co/
:alt: Jazzband

This is a Jazzband <https://jazzband.co>_ project. By contributing you agree
to abide by the Contributor Code of Conduct <https://jazzband.co/about/conduct>_ and follow the guidelines <https://jazzband.co/about/guidelines>_.


File: RELEASING.rst

Preparing a Release

The following steps are needed to prepare a release:

  1. Make sure the VERSION in django_redis/__init__.py has been updated.
  2. Run towncrier build to update the CHANGELOG.rst with the
    news fragments for the release.
  3. Commit the changes for steps 1 and 2.
  4. Tag the commit with the same version as specified for VERSION in step 1.
  5. Wait for the release action_ to complete, which will upload the package
    to django-redis jazzband_, and when it's complete you can then release
    the package to PyPI.

.. _release action: https://github.com/jazzband/django-redis/actions/workflows/release.yml
.. _django-redis jazzband: https://jazzband.co/projects/django-redis


File: .pre-commit-config.yaml

repos:


File: tests/README.rst

Running the test suite

.. code-block:: bash

start redis and a sentinel (uses docker with image redis:alpine)

docker compose -f tests/compose.yml up --detach --wait


File: tests/compose.yml

services:
redis:
image: redis:alpine
healthcheck:
test: ['CMD', 'redis-cli', 'ping']
start_period: 1m
start_interval: 1s
ports:
- 6379:6379

redis-sentinel:
command:
# Force sh as the shell as the multiline quoted string below is not
# being written correctly, and it's not clear what shell is being run.
- sh
- -c
# Generate a sentinel configuration that is writable by the sentinel
- |
echo '
sentinel resolve-hostnames yes
sentinel monitor redis redis 6379 1
sentinel down-after-milliseconds redis 3200
sentinel failover-timeout redis 10000
sentinel parallel-syncs redis 1
' > /etc/redis-sentinel.conf

text
exec redis-server /etc/redis-sentinel.conf --sentinel
depends_on:
  redis:
    condition: service_healthy
image: redis:alpine
healthcheck:
  test: ['CMD', 'redis-cli', '-p', '26379', 'ping']
  start_period: 1m
  start_interval: 1s
ports:
  - 26379:26379

File: .github/codecov.yml

coverage:

small changes should not fail coverage

precision: 1
round: up

status:
project:
default:
target: auto
mypy:
target: auto
flags:
- mypy

text
tests:
    target: auto
    flags:
      - tests

File: .github/dependabot.yml

To get started with Dependabot version updates, you'll need to specify which

package ecosystems to update and where the package manifests are located.

Please see the documentation for all configuration options:

https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates

version: 2
updates:

  • package-ecosystem: "github-actions"
    directory: "/" # Location of package manifests
    schedule:
    interval: "daily"

File: .github/ISSUE_TEMPLATE/bug_report.md


name: Bug report
about: Create a report to help us improve
labels: bug


Describe the bug
A clear and concise description of what the bug is.

To Reproduce
Steps to reproduce the behavior:

  1. Go to '...'
  2. Click on '....'
  3. Scroll down to '....'
  4. See error

Expected behavior
A clear and concise description of what you expected to happen.

Stack trace
If applicable, add stack trace to help explain your problem.

Environment (please complete the following information):

  • Python version: [e.g. 3.5]
  • Django Redis Version: [e.g. 1.9.1]
  • Django Version: [e.g. 1.11.11]
  • Redis Version: [e.g. 2.5.0]
  • redis-py Version: [e.g. 3.5.0]

Additional context
Add any other context about the problem here.


File: .github/ISSUE_TEMPLATE/feature_request.md


name: Feature request
about: Suggest an idea for this project


Problem Statement
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]

Describe the solution you'd like
A clear and concise description of what you want to happen.

Describe alternatives you've considered
A clear and concise description of any alternative solutions or features you've considered.

Additional context
Add any other context or screenshots about the feature request here.


File: .github/ISSUE_TEMPLATE/question.md


name: Question
about: Create question to us
title: ''
labels: question
assignees: ''



File: .github/workflows/ci.yml

name: CI

on: [push, pull_request]

jobs:
test:
name: >
Test Python ${{ matrix.python-version }},
Django ${{ matrix.django-version }},
Redis.py ${{ matrix.redis-version }}

text
runs-on: ubuntu-latest

strategy:
  fail-fast: false
  matrix:
    python-version:
      - '3.12'
      - '3.13'
      - '3.14'
    django-version:
      - '5.2'
      - '6.0'
    redis-version:
      - 'latest'

    include:
      # Django 5.2 supports Python 3.10 & Python 3.11
      - python-version: '3.10'
        django-version: '5.2'
      - python-version: '3.11'
        django-version: '5.2'

      # Only test pre-release dependencies for the latest Python.
      # latest Django with pre-release redis
      - python-version: '3.14'
        django-version: '6.0'
        redis-version: 'master'

      # pre-release Django with latest redis
      - python-version: '3.14'
        django-version: 'main'
        redis-version: 'latest'

      # pre-release Django and pre-release redis
      - python-version: '3.14'
        django-version: 'main'
        redis-version: 'master'

steps:
  - uses: actions/checkout@v6

  - name: Set up Python ${{ matrix.python-version }}
    uses: actions/setup-python@v6
    with:
      python-version: ${{ matrix.python-version }}

  - name: Get pip cache dir
    id: pip-cache
    run: |
      echo "::set-output name=dir::$(pip cache dir)"

  - name: Cache
    uses: actions/cache@v5
    with:
      path: ${{ steps.pip-cache.outputs.dir }}
      key: pip-test-python-${{ matrix.python-version }}-django-${{ matrix.django-version }}-redis-${{ matrix.redis-version }}-${{ hashFiles('**/pyproject.toml') }}
      restore-keys: |
        pip-test-python-${{ matrix.python-version }}-django-${{ matrix.django-version }}-redis-${{ matrix.redis-version }}
        pip-test-python-${{ matrix.python-version }}
        pip-test-

  - name: Install dependencies
    run: |
      python -m pip install --upgrade pip
      python -m pip install --upgrade tox-uv tox-gh

  - name: Docker compose up
    run: docker compose -f tests/compose.yml up --detach --wait

  - name: Tox tests
    run: tox
    env:
      DJANGO: ${{ matrix.django-version }}
      REDIS: ${{ matrix.redis-version }}

  - name: Docker compose down
    if: ${{ !cancelled() }}
    run: docker compose -f tests/compose.yml down

  - name: Upload coverage
    uses: codecov/codecov-action@v7
    with:
      env_vars: DJANGO,REDIS,PYTHON
      flags: tests
    env:
      DJANGO: ${{ matrix.django-version }}
      REDIS: ${{ matrix.redis-version }}
      PYTHON: ${{ matrix.python-version }}

lint:
name: Lint (${{ matrix.tool }})
runs-on: ubuntu-latest

text
strategy:
  fail-fast: false
  matrix:
    tool:
      - 'pre-commit'
      - 'mypy'

steps:
  - uses: actions/checkout@v6

  - name: Set up Python
    uses: actions/setup-python@v6
    with:
      python-version: '3.x'

  - name: Get pip cache dir
    id: pip-cache
    run: |
      echo "::set-output name=dir::$(pip cache dir)"

  - name: Cache
    uses: actions/cache@v5
    with:
      path: ${{ steps.pip-cache.outputs.dir }}
      key: pip-lint-${{ hashFiles('**/pyproject.toml') }}
      restore-keys: |
        pip-lint-

  - name: Install dependencies
    run: |
      python -m pip install --upgrade pip
      python -m pip install --upgrade tox

  - name: Run ${{ matrix.tool }}
    run: tox -e ${{ matrix.tool }}

  - name: Upload coverage
    if: ${{ matrix.tool == 'mypy' }}
    uses: codecov/codecov-action@v7
    with:
      flags: mypy

check-changelog:
name: Check for news fragments in 'changelog.d/'
runs-on: ubuntu-latest

text
steps:
  - uses: actions/checkout@v6
    with:
      fetch-depth: 0

  - name: Set up Python
    uses: actions/setup-python@v6
    with:
      python-version: '3.x'

  - name: Get pip cache dir
    id: pip-cache
    run: |
      echo "::set-output name=dir::$(pip cache dir)"

  - name: Cache
    uses: actions/cache@v5
    with:
      path: ${{ steps.pip-cache.outputs.dir }}
      key: pip-check-changelog-${{ hashFiles('**/pyproject.toml') }}
      restore-keys: |
        pip-check-changelog-

  - name: Install dependencies
    run: |
      python -m pip install --upgrade pip
      python -m pip install --upgrade towncrier

  - name: Run towncrier check
    run: |
      if ! towncrier check; then
        echo ''
        echo "Please add a description of your changes to 'changelog.d/{issue or PR number}.{feature,bugfix,misc,doc,removal}'"
        exit 1
      fi

File: .github/workflows/release.yml

name: Release

on:
push:
tags:
- '*'

jobs:
build:
if: github.repository == 'jazzband/django-redis'
runs-on: ubuntu-latest

text
steps:
  - uses: actions/checkout@v6
    with:
      fetch-depth: 0

  - name: Set up Python
    uses: actions/setup-python@v6
    with:
      python-version: 3.9

  - name: Install dependencies
    run: |
      python -m pip install --upgrade pip
      python -m pip install --upgrade build twine

  - name: Build package
    run: |
      python -m build
      twine check dist/*

  - name: Upload packages to Jazzband
    if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags')
    uses: pypa/gh-action-pypi-publish@master
    with:
      user: jazzband
      password: ${{ secrets.JAZZBAND_RELEASE_KEY }}
      repository_url: https://jazzband.co/projects/django-redis/upload