2010-04-22 18 views
10

Mam abstrakcyjny model przechowujący pamięć podręczną na dysku. Kiedy usuwam model, potrzebuję go do usunięcia pamięci podręcznej. Chcę, aby tak się stało również dla każdego modelu pochodnego.Jak używać sygnałów Django z abstrakcyjnym modelem?

Jeśli mogę podłączyć sygnał określający abstrakcyjny model ten nie rozprzestrzeniać do modeli pochodnych:

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

Gdy próbuję podłączyć sygnał w init,, gdzie mogę dostać klasie pochodnej nazwa, działa, ale obawiam się, że spróbuje wyczyścić pamięć podręczną tyle razy, ile zainicjowałem model pochodny, a nie tylko raz.

Gdzie powinienem podłączyć sygnał?

Odpowiedz

4

Utwórz niestandardowy menedżer dla swojego modelu. W metodzie contribute_to_class ustaw sygnał dla class_prepared. Ten sygnał wywołuje funkcję, która wiąże więcej sygnałów z modelem.

+1

Wpadłem na pomysł, ale czy mógłbyś podać przykład? To naprawdę pomogłoby utrzymać rzeczy DRY w moim bieżącym projekcie. –

+0

Edytuj: Próbowałem pracować nad Twoją sugestią w mojej własnej odpowiedzi. Działa to dla mnie, ale nie jestem w 100% pewny! –

+0

Nie ma oficjalnego dokumentu dla 'contribute_to_class' ... – Raffi

2

Myślę, że możesz połączyć się z post_delete bez określania nadawcy, a następnie sprawdź, czy aktualny nadawca znajduje się na liście klas modeli. Coś takiego:

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

Oczywiście potrzebujesz bardziej wyrafinowanych sprawdzeń itp., Ale wpadłeś na pomysł.

3

Bazując na odpowiedzi Justina Lilly, stworzyłem niestandardowego menedżera, który wiąże sygnał post_save z każdym dzieckiem klasy, czy to abstrakcyjnym, czy nie.

To jest jednorazowy, źle przetestowany kod, więc uważaj! Jak dotąd działa.

W tym przykładzie zezwalamy na abstrakcyjny model do definiowania CachedModelManager jako menedżera, który rozszerza podstawową funkcję buforowania do modelu i jego elementów podrzędnych. Pozwala zdefiniować listę zmiennych kluczy, które powinny zostać usunięte przy każdym zapisie (stąd sygnał post_save) i dodaje kilka funkcji pomocniczych do generowania kluczy cache, a także do pobierania, ustawiania i usuwania kluczy.

Zakłada to oczywiście, że masz konfigurację bufora pamięci podręcznej i działa poprawnie.

# 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 

Patche witamy!

+0

Zamieniono go na fragment: http://djangosnippets.org/snippets/2749/ –

Powiązane problemy