2010-04-22 28 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