Сигнал Django post_save для родительского класса с многотабличным наследованием

В Django, если у вас есть модели, использующие наследование с несколькими таблицами, и вы определяете приемник для сигнала post_save в родительском классе, вызывается ли эта функция приемника при сохранении экземпляра дочернего класса?

Заимствуя пример из другого вопроса:

class Animal(models.Model):
    category = models.CharField(max_length=20)

class Dog(Animal):
    color = models.CharField(max_length=10)

def echo_category(sender, **kwargs):
    print "category: '%s'" % kwargs['instance'].category

post_save.connect(echo_category, sender=Animal)

If I do:

>>> dog = Dog.objects.get(...)
>>> dog.category = "canine"
>>> dog.save()

Будет ли вызываться функция получателя echo_category?


person Lorin Hochstein    schedule 07.02.2013    source источник


Ответы (4)


Проверьте: https://code.djangoproject.com/ticket/9318 Похоже, что большинство сигнал суперу в подклассе.

person bfschott    schedule 07.02.2013

post_save.connect(my_handler, ParentClass)
# connect all subclasses of base content item too
for subclass in ParentClass.__subclasses__():
    post_save.connect(my_handler, subclass)

хорошего дня!

person scythargon    schedule 08.07.2014
comment
Куда вы можете безопасно поместить этот фрагмент, чтобы все подклассы уже были зарегистрированы? - person Scott Stafford; 09.03.2016
comment
@ScottStafford В методе готовности приложения - person Dave Lawrence; 16.10.2017

Нет, не назовут. См. #9318 в Django trac.

person Lorin Hochstein    schedule 07.02.2013

Мне удалось заставить унаследованные приемники сигналов работать с декоратором @receiver. См. соответствующую документацию по Django< /а>

from django.db import models
from django.db.models.signals import post_save
from django.dispatch import receiver

class Animal(models.Model):
    category = models.CharField(max_length=20)

    @receiver(post_save)
    def echo_category(sender, **kwargs):
        print ("category: '%s'" % kwargs['instance'].category)

class Dog(Animal):
    color = models.CharField(max_length=10)

Это решение действительно в Python 3.6.8 Django 2.2.

Когда я делаю это

>>> from myapp.models import Dog
>>> dog = Dog()
>>> dog.category = "canine"
>>> dog.save()
category: 'canine'
>>>

Нет проблем. Вроде все работает из шелла.


Немного не связано, но когда я редактировал модели через панель администратора, возникла проблема с двойным вызовом, поэтому я отфильтровал их, проверив 'created' kwarg. В одном вызове это было ложно, в другом — верно, поэтому я просто вставил простой блок if. Кредит на этот обходной путь принадлежит Pratik Mandrekar и его ответ:

from django.db import models
from django.db.models.signals import post_save
from django.dispatch import receiver

class Animal(models.Model):
    category = models.CharField(max_length=20)

    @receiver(post_save)
    def echo_category(sender, **kwargs):
        if not kwargs.get('created'):
            print ("category: '%s'" % kwargs['instance'].category)

class Dog(Animal):
    color = models.CharField(max_length=10)
person Benargee    schedule 25.05.2019
comment
Я пробовал это, но приемник, кажется, вызывается всякий раз, когда по какой-то причине создается ЛЮБАЯ модель. - person Mazino; 03.05.2020