2010-04-22 58 views
10

我有一个保持磁盘缓存的抽象模型。当我删除模型时,我需要它删除缓存。我希望这也发生在每个派生模型上。如何在抽象模型中使用Django信号?

如果我连接指定的抽象模型的信号,这不会传播到派生出来的型号:

pre_delete.connect(clear_cache, sender=MyAbstractModel, weak=False) 

如果我尝试了信号在初始化,连接在那里我能得到的派生类名称,它的工作原理,但恐怕它会尝试清除缓存多次,因为我已经初始化派生模型,而不仅仅是一次。

我应该在哪里连接信号?

回答

4

为您的模型创建一个自定义管理器。在其contribute_to_class方法中,让它为class_prepared设置一个信号。该信号调用将更多信号绑定到模型的功能。

+1

我明白这个背后的想法,但是你可以用一个例子来阐述一下吗?这将有助于保持我目前项目的干爽。 – 2012-05-15 14:47:39

+0

编辑:我试着在你自己的答案中提出你的建议..它适用于我,但我不是100%确定! – 2012-05-15 16:29:33

+0

没有官方的文档'contribute_to_class' ... – Raffi 2017-11-13 08:48:30

2

我想你可以连接到post_delete而不指定发件人,然后检查实际发件人是否在模型类列表中。就像:

def my_handler(sender, **kwargs): 
    if sender.__class__ in get_models(someapp.models): 
     ... 

显然你需要更复杂的检查等,但你明白了。

3

基于贾斯汀莉莉的回答,我创建了一个自定义管理器,它将post_save信号绑定到类的每个孩子,无论是否抽象。

这是一次性的,测试不当的代码,所以要小心!尽管如此,它仍然有效。

在此示例中,我们允许抽象模型将CachedModelManager定义为管理器,然后将基本高速缓存功能扩展到模型及其子级。它允许您定义每次保存时应删除的易失性密钥列表(因此是post_save信号),并添加一些辅助函数来生成缓存密钥,以及检索,设置和删除密钥。

这当然假设您有一个缓存后端设置并正常工作。

# 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 

修补程序欢迎!

+0

将它变成一个片段:http://djangosnippets.org/snippets/2749/ – 2012-05-16 21:05:09