Django-Cacheme is a memoized decorator for Django using redis

cache, django, memoization, python, redis
pip install django-cacheme==0.1.3


Build Status Build Status


Django-Cacheme is a memoized/cache package for Django based on Cacheme.


Cacheme features:

Django-Cacheme extend Cacheme to support Django settings, and integrate Django model signals automatically. Also provide an admin page to manage your cache.

Getting started

  • pip install django-cacheme

  • Add django_cacheme to your INSTALLED_APPS

  • Update Django settings, Django-Cacheme will initialize cacheme automatically:

    'ENABLE_CACHE': True,
    'REDIS_CACHE_ALIAS': 'cacheme',  # your CACHES alias name in settings, optional, 'default' as default
    'REDIS_CACHE_PREFIX': 'MYCACHE:',  # cacheme key prefix, optional, 'CM:' as default
    'THUNDERING_HERD_RETRY_COUNT': 5,  # thundering herd retry count, if key missing, default 5
    'THUNDERING_HERD_RETRY_TIME': 20,  # thundering herd wait time(millisecond) between each retry, default 20
    'STALE': True  # Global setting for using stale, default True
  • Finally run migrate before use

How to use

Read cacheme doc first:

- Cacheme Decorator

Django-Cacheme add new parameters to cacheme decorator:

invalid_models/invalid_m2m_models: List, default []. Models and m2m models that will trigger the invalid signal, every model must has an invalid_key property(can be a list), and m2m model need m2m keys(see Model part). And when signal is called, all members in the model instance invalid key will be removed.

- Model property/attribute

To make invalid signal work, you need to define property for models that connect to signals in As you can see in the example, a cache_key property is needed. And when invalid signal is triggered, signal func will get this property value, add ':invalid' to it, and then invalid all keys store in this key.

class Book(models.Model):

    def cache_key(self):
        return "Book:%s" %

This is enough for simple models, but for models include m2m field, we need some special rules. For example, Book model has a m2m field to User, and if we do: book.users.add(users), We have two update, first, book.users changed, because a new user is add to this. Second, user.books also change, because this user has a new book. And on the other side, if we do user.books.add(books), also get two updates. So if you take a look on, you will notice I add a m2m_cache_keys dict to through model, that's because both book.add() and user.add() will trigger the m2m invalid signal, but the first one, signal instance will be book, and pk_set will be users ids, and the second one, signal instance will be user, pk_set will be books ids. So the invalid keys is different depend the instance in signal function.

Book.users.through.m2m_cache_keys = {

    # book is instance, so pk_set are user ids, used in signal book.users.add(users)
    'Book': lambda ids: ['User:%s:books' % id for id in ids],

    # user is instance, so pk_set are book ids, used in signal user.books.add(books)
    'TestUser': lambda ids: ['Book:%s:users' % id for id in ids],


- Model based Node

Django-Cacheme add a new invalid node class called ModelInvalidNode, this class handle model signal automatically for you. So no need to add property/attribute to model.

Model without m2m, just add model = YourModel to invalid node meta attributes. This will connect post_save/delete signals automatically. You can use instance directly in ModelInvalidNode, for example, invalid_nodes.InvalidUserNode(instance=self.user), ModelInvalidNode will get values for all fields from this instance.

Model with m2m is special, you need to use intermediate model in node. First add model = YourIntermediateModel and m2m = True to class meta. Then Add fk fields in intermediate model as nodes.Field. For example,UserBook model has 2 foreign keys user and book, yours fields in InvalidNode will be user and book. You can use either InvalidUserBookNode(user=self.user) or InvalidUserBookNode(, first one will create invalid key: user:{user_id}:book:all, second one will create invalid key user:all:book:{book_id}. str/int as field value is also support, for example InvalidUserBookNode(user=12), will create key user:12:book:all


from django_cacheme import nodes

class InvalidUserNode(nodes.ModelInvalidNode):
    id = nodes.Field()

    def key(self):
        return 'user:%s' %

    class Meta:
        model = models.User

class UserNode(nodes.Node):
    user = nodes.Field()

    def key(self):
        return 'user:%s' %

    def invalid_nodes(self):
        return [

# create invalidation manually

# get fields from instance automatically
# or using field explictly

Example M2M:

from django_cacheme import nodes

class InvalidUserBookNode(nodes.ModelInvalidNode):
    user = nodes.Field()
    book = nodes.Field()

    def key(self):
        return 'user:%s:book:%s' % (self.testuser,

    class Meta:
        model = models.TestUser.books.through
        m2m = True

class UserBookNode(nodes.Node):
    user = nodes.Field()

    def key(self):
        return 'user:%s' %

    def invalid_nodes(self):
        return [

# create invalidation manually