Джанго сигнал через декоратор на метод модели? - PullRequest
8 голосов
/ 22 февраля 2010

Я пытаюсь сделать что-то вроде этих предложенных декораторов сигналов . В дополнение к наличию декоратора, который соединяет декорированный метод с сигналом (с отправителем сигнала в качестве аргумента декоратору), я хотел бы использовать декоратор в методах класса.

Я бы хотел использовать декоратор так:

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 работает под капотом, но из этой справочной страницы я предполагаю, что объект метода класса не переводится в вызываемый объект до тех пор, пока к нему не получит доступ класс, например 1018 *. Есть ли способ, которым я могу (1) определить мой метод как метод класса или экземпляра в модели и (2) подключить его к сигналу, используя декоратор непосредственно в определении метода? Спасибо!

Ответы [ 3 ]

2 голосов
/ 15 июля 2010

Не могли бы вы вместо этого сделать @staticmethod? Таким образом, вы можете просто поменять порядок декораторов.

class ModelA(Model):

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

Вы должны ссылаться на класс по полному имени, а не передавать аргумент cls, но это позволит вам сохранить подобную организацию кода.

2 голосов
/ 04 марта 2010

Это не ясно из вашего примера кода, поэтому я спрашиваю, действительно ли прослушиватель сигналов должен быть @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)
0 голосов
/ 19 августа 2016

Исходя из ответа Мэтта, трюк @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
...