Basándome en la respuesta de Justin Lilly, he creado un administrador personalizado que vincula una señal post_save a cada elemento secundario de una clase, ya sea abstracto o no.
Este es un código único, poco probado, así que ¡cuidado! Sin embargo, funciona hasta ahora.
En este ejemplo, permitimos que un modelo abstracto defina CachedModelManager como administrador, que luego amplía la funcionalidad básica de caché para el modelo y sus elementos secundarios. Le permite definir una lista de claves volátiles que se deben eliminar cada vez que se guarde (de ahí la señal post_save) y agrega un par de funciones auxiliares para generar claves de caché, así como para recuperar, configurar y eliminar claves.
Esto, por supuesto, asume que tiene una configuración de back-end de caché y funciona correctamente.
# helperapp\models.py
# -*- coding: UTF-8
from django.db import models
from django.core.cache import cache
class CachedModelManager(models.Manager):
def contribute_to_class(self, model, name):
super(CachedModelManager, self).contribute_to_class(model, name)
setattr(model, 'volatile_cache_keys',
getattr(model, 'volatile_cache_keys', []))
setattr(model, 'cache_key', getattr(model, 'cache_key', cache_key))
setattr(model, 'get_cache', getattr(model, 'get_cache', get_cache))
setattr(model, 'set_cache', getattr(model, 'set_cache', set_cache))
setattr(model, 'del_cache', getattr(model, 'del_cache', del_cache))
self._bind_flush_signal(model)
def _bind_flush_signal(self, model):
models.signals.post_save.connect(flush_volatile_keys, model)
def flush_volatile_keys(sender, **kwargs):
instance = kwargs.pop('instance', False)
for key in instance.volatile_cache_keys:
instance.del_cache(key)
def cache_key(instance, key):
if not instance.pk:
name = "%s.%s" % (instance._meta.app_label, instance._meta.module_name)
raise models.ObjectDoesNotExist("Can't generate a cache key for " +
"this instance of '%s' " % name +
"before defining a primary key.")
else:
return "%s.%s.%s.%s" % (instance._meta.app_label,
instance._meta.module_name,
instance.pk, key)
def get_cache(instance, key):
result = cache.get(instance.cache_key(key))
return result
def set_cache(instance, key, value, timeout=60*60*24*3):
result = cache.set(instance.cache_key(key), value, timeout)
return result
def del_cache(instance, key):
result = cache.delete(instance.cache_key(key))
return result
# myapp\models.py
from django.contrib.auth.models import User
from django.db import models
from helperapp.models import CachedModelManager
class Abstract(models.Model):
creator = models.ForeignKey(User)
cache = CachedModelManager()
class Meta:
abstract = True
class Community(Abstract):
members = models.ManyToManyField(User)
volatile_cache_keys = ['members_list',]
@property
def members_list(self):
result = self.get_cache('members_list')
if not result:
result = self.members.all()
self.set_cache('members_list', result)
return result
Parches welcome!
Tengo la idea detrás de esto, pero ¿podría elaborar con un ejemplo? Esto realmente ayudaría a mantener las cosas SECAS en mi proyecto actual. –
Editar: Traté de trabajar en su sugerencia en mi propia respuesta ... funciona para mí, pero no estoy 100% seguro! –
No hay un documento oficial para 'contribute_to_class' ... – Raffi