Skip to content

Instantly share code, notes, and snippets.

@kesor
Created October 3, 2011 19:45
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kesor/1260033 to your computer and use it in GitHub Desktop.
Save kesor/1260033 to your computer and use it in GitHub Desktop.
Caching for GenericRelation models in Django
from django.db import models
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes import generic
from django.core.cache import cache
from django.dispatch import receiver
class LabelsManager(models.Manager):
""" The manager for Label/s, as well as superclass of the RelatedManager/s of Label/s """
def all(self):
if hasattr(self, 'instance'):
cache_key = '_%s_%s_%s' % (
self.model._meta.db_table,
self.instance.content_type.id,
self.instance.pk
)
result = cache.get(cache_key)
if result is not None:
return result
result = super(LabelsManager, self).all()
cache.set(cache_key, result)
return result
return super(LabelsManager, self).all()
class Label(models.Model):
objects = LabelsManager()
name = models.CharField(max_length=64)
content_type = models.ForeignKey(ContentType)
object_id = models.PositiveIntegerField()
related_object = generic.GenericForeignKey('content_type', 'object_id')
@receiver(models.signals.post_save, sender=Label)
@receiver(models.signals.pre_delete, sender=Label)
def cache_invalidate_signal_handler(sender, instance, **kwargs):
cache_key = '_%s_%s_%s' % (
instance._meta.db_table,
instance.content_type.id,
instance.object_id
)
cache.delete(cache_key)
@pandafy
Copy link

pandafy commented Jun 19, 2020

Will it even work?

https://github.com/django/django/blob/27c09043da52ca1f02605bf28600bfd5ace95ae4/django/db/models/manager.py#L149-L156

From Django's Source Code:

    def all(self):
        # We can't proxy this method through the `QuerySet` like we do for the
        # rest of the `QuerySet` methods. This is because `QuerySet.all()`
        # works by creating a "copy" of the current queryset and in making said
        # copy, all the cached `prefetch_related` lookups are lost. See the
        # implementation of `RelatedManager.get_queryset()` for a better
        # understanding of how this comes into play.
        return self.get_queryset()

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment