关于python:django信号通过decorator上的模型方法?

Django Signal via Decorator on Model Method?

我正试图做一些类似于这些被提议的信号装饰器的事情。除了有一个将修饰方法连接到信号的修饰器(信号的发送者作为修饰器的参数),我还想在类方法上使用修饰器。

我想用这样的装饰:

1
2
3
4
5
6
7
class ModelA(Model):

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

装饰师是:

1
2
3
4
5
6
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

当我这样做时,我得到的错误是:

1
2
File"/Library/Python/2.6/site-packages//lib/python2.6/site-packages/django/dispatch/dispatcher.py", line 78, in connect
AssertionError: Signal receivers must be callable.

我想问题是@classmethod返回了一个不可调用的类方法对象。我不太明白classmethod是如何在引擎盖下工作的,但我从这个引用页推测,在从类(例如,ModelA.observe_model_b_saved访问它之前,类方法对象不会转换为可调用的。是否有任何方法可以(1)将我的方法定义为模型上的类或实例方法,以及(2)直接使用方法定义上的修饰符将其连接到信号?谢谢!


可以改为@staticmethod吗?这样,您就可以交换装饰师的订单。

1
2
3
4
5
6
7
class ModelA(Model):

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

您必须用全名引用类,而不是传递cls参数,但这将允许您保持类似的代码组织。


从您的示例代码中还不清楚,所以我会问信号监听器实际上是否必须是一个@classmethod?也就是说,如果仍然需要访问类本身,常规方法是否可以(然后使用EDOCX1[1])?它是否需要是一个方法(您可以只使用一个函数)?

另一种选择可能是使用第二种方法来监听信号并将调用委托给@classmethod

1
2
3
4
5
6
7
8
9
10
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)


根据马特的回答,@staticmethod技巧对我很有效。可以使用字符串非具体地引用模型。

1
2
3
4
5
6
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