Мне нужно подключить сигнал django для всех классов, которые наследуются от абстрактного класса. Существует ли такой магический метод python, как __on_inherit__, который позволял бы мне запускать код подключения сигнала каждый раз, когда мой абстрактный класс наследуется?

Обновление: просто для пояснения мне нужно запускать код оценки класса один раз для каждого класса, а не один раз для экземпляра / объекта.

2
timthelion 27 Июн 2019 в 11:45

2 ответа

Лучший ответ

Мы можем реализовать решение для этого. Сначала мы можем сгенерировать набор подклассов абстрактной модели, например, с помощью этого решения:

def get_descendants(klass):
    gen = { klass }
    desc = set()
    while gen:
        gen = { skls for kls in gen for skls in kls.__subclasses__() }
        desc.update(gen)
    return desc

Далее мы можем повторить это и каждый раз вызывать функцию, например:

for subclass in get_descendants(AbstractModel):
    # ... do something with that subclass
    pass

Где AbstactModel - это абстрактная модель, из которой вы хотите получить подклассы.

Вы должны инициировать оценку этого при загрузке приложений, например, в ready() метод [Django-doc] из AppConfig.

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

Пример : добавление сигнала в каждый подкласс

Например, мы можем добавить сигнал к каждому подклассу AbstractModel , сначала определив обработчик сигнала:

def test_signal(sender, instance, **kwargs):
    print('{} is saved'.format(instance))

И тогда мы можем связать его с каждым подклассом:

from django.db.models.signals import post_save

for subclass in get_descendants(AbstractModel):
    post_save.connect(test_signal, sender=subclass)
2
Willem Van Onsem 27 Июн 2019 в 08:59

Да, действительно, есть ловушка [__init_subclass__] [1], которая запускается каждый раз, когда класс находится в подклассе.

Он будет вызываться с первым аргументом cls как подкласс new (не исходный родительский класс). Как указано в документации, вы можете даже передавать произвольные аргументы в ловушку от дочерних классов.

Надеюсь, это поможет вам.

Изменить : это было добавлено с помощью PEP 487 [2] в Python версии 3.6. В более ранних версиях Python этот метод не вызывался.

[1] https://docs.python.org/3/reference /datamodel.html#object . < сильный > init_subclass

[2] https://www.python.org/dev/peps/pep- 0487 /

3
timthelion 27 Июн 2019 в 10:45