Django信号在模型方法上使用装饰器?
我正在尝试做一些类似于这些提议的信号装饰器的事情。除了有一个装饰器可以将被装饰的方法连接到一个信号(装饰器的参数是信号的发送者)之外,我还想在类的方法上使用这个装饰器。
我想这样使用这个装饰器:
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
是怎么工作的,但我从这个参考页面中推测,类方法对象在被类访问之前是不会变成可调用的,比如说ModelA.observe_model_b_saved
。有没有办法让我同时做到(1)在模型上将我的方法定义为类方法或实例方法,以及(2)直接在方法定义上使用装饰器将其连接到信号?谢谢!
3 个回答
2
根据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
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)
3
你能把它改成一个 @staticmethod 吗?这样的话,你只需要调换一下装饰器的顺序就可以了。
class ModelA(Model):
@staticmethod
@connect.post_save(ModelB)
def observe_model_b_saved(sender, instance, created, **kwargs):
# do some stuff
pass
你需要用类的全名来引用它,而不是像之前那样通过 cls 参数传递过来,但这样可以让你的代码结构保持相似。