Я пытаюсь сделать что-то как эти предложенные декораторы сигнала. В дополнение к наличию декоратора, который подключает украшенный метод к сигналу (с отправителем сигнала как аргумент декоратору), я хотел бы использовать декоратора на методах класса.
Я хотел бы использовать декоратора как так:
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) подключить его к сигналу с помощью декоратора непосредственно на определении метода?Спасибо!
Это не ясно из вашего примера кода, поэтому я бы спросил, действительно ли слушателем сигнала должен быть @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)
Не могли бы вы вместо этого сделать @staticmethod? Тогда вы сможете просто поменять порядок декораторов.
class ModelA(Model):
@staticmethod
@connect.post_save(ModelB)
def observe_model_b_saved(sender, instance, created, **kwargs):
# do some stuff
pass
Вам придется обращаться к классу по полному имени вместо того, чтобы передавать аргумент cls, но это позволит вам сохранить схожую организацию кода.