Django Signal a través de Decorator en el método de modelo?

Estoy tratando de hacer algo como estos decoradores de señales propuestos . Además de tener un decorador que conecta el método decorado a una señal (con el remitente de la señal como argumento al decorador), me gustaría usar el decorador en los métodos de clase.

Me gustaría usar el decorador así:

class ModelA(Model): @connect.post_save(ModelB) @classmethod def observe_model_b_saved(cls, sender, instance, created, **kwargs): # do some stuff pass 

El decorador es:

 from django.db.models import signals def post_save(sender): def decorator(view): signals.post_save.connect(sender=sender, receiver=view) return view return decorator 

El error que recibo cuando hago esto es:

 Archivo "/Library/Python/2.6/site-packages//lib/python2.6/site-packages/django/dispatch/dispatcher.py", línea 78, en conexión
 Error de aserción: los receptores de señales deben ser invocables.

Supongo que el problema es que @classmethod devuelve un objeto de método de clase que no se puede llamar. Realmente no entiendo cómo funciona el método de clase bajo el capó, pero supongo que, a partir de esta página de referencia, el objeto del método de la clase no se traduce en un llamable hasta que se accede desde la clase, por ejemplo, ModelA.observe_model_b_saved . ¿Hay alguna manera en que pueda (1) definir mi método como un método de clase o instancia en un modelo, y (2) conectarlo a una señal usando un decorador directamente en la definición del método? ¡Gracias!

No está claro en su código de ejemplo, por lo que me preguntaría si el oyente de la señal realmente tiene que ser un @classmethod ? Es decir, ¿un método regular funcionará (y luego usará self.__class__ si aún necesita acceder a la clase en sí)? ¿Es necesario que sea un método (puedes usar una función)?

Otra opción podría ser usar un segundo método para escuchar la señal y delegar la llamada a @classmethod :

 class ModelA(Model): @classmethod def do_observe_model_b_saved(cls, sender, instance, created, **kwargs): # do some stuff pass @connect.post_save(ModelB) def observe_model_b_saved(self, sender, instance, created, **kwargs): self.do_observe_model_b_saved(sender, instance, created, **kwargs) 

¿Podrías convertirlo en un método @estático? De esa manera, puedes cambiar el orden de los decoradores.

 class ModelA(Model): @staticmethod @connect.post_save(ModelB) def observe_model_b_saved(sender, instance, created, **kwargs): # do some stuff pass 

Tendría que referirse a la clase por su nombre completo en lugar de pasar el argumento cls, pero esto le permitiría mantener una organización de código similar.

Basado en la respuesta de Matt, el truco de @staticmethod funcionó para mí. Puede utilizar una cadena para hacer referencia a un modelo de forma no concreta.

 class Foo(Model): @staticmethod @receiver(models.signals.post_save, sender='someappname.Foo') def post_save(sender, instance, created, **kwargs): print 'IN POST SAVE', sender, instance.id, created