模型方法的装饰器Django信号?

时间:2010-02-22 11:58:46

标签: python django django-models decorator django-signals

我正在尝试做these proposed signal decorators之类的事情。除了有一个装饰器将装饰方法连接到一个信号(信号的发送者作为装饰器的参数),我想在类方法上使用装饰器。

我想像这样使用装饰器:

class ModelA(Model):

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

装饰者是:

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

我这样做的错误是:

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如何在幕后工作,但我从this reference page推测,在从类中访问类方法对象之前,它不会被转换为可调用的,例如{{1} }}。有没有什么办法我可以(1)将我的方法定义为模型上的类或实例方法,以及(2)直接在方法定义上使用装饰器将其连接到信号?谢谢!

3 个答案:

答案 0 :(得分:2)

从你的示例代码中不清楚,所以我会问,信号监听器实际上是否必须是@classmethod?即常规方法会不会(如果您仍需要访问类本身,则使用self.__class__)?是否需要一个方法(你能使用一个函数)?

另一种选择可能是使用第二种方法来收听信号并将呼叫委托给@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)

答案 1 :(得分:2)

你可以改成@static方法吗?这样,您就可以交换装饰器的顺序。

class ModelA(Model):

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

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

答案 2 :(得分:0)

基于Matt的回答,@ staticmethod技巧对我有用。您可以使用字符串非具体地引用模型。

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