При использовании типов Generics, как я могу вызвать атрибут наследуемого класса на экземпляре базового класса в Python / Django?

Допустим, у меня есть базовый класс Generic под названием person для группировки всех других person, которые расширяют его:

class Person(models.Model):
    name = models.CharField(...)

И класс Worker, который расширяет Person:

class Worker(Person):
    card_id = models.CharField(...)

Когда я обращаюсь ко всем объектам Person, я также вижу Workers, но допустим, что оттуда я хочу сделать следующее:

worker = Worker(name='Example', card_id='1234')

person = Person.objects.all().first()

Допустим, по какой-то причине я хочу использовать класс Person и вызвать атрибут o Worker:

[in] person.card_id
# Somehow expecting this result:
[out] '1234

Возможно ли это, жизнеспособно ли это и как мне это сделать?

Боюсь, что это невозможно, даже если вы можете гарантировать, что извлеченный вами объект Person (т.е. Person.objects.all().first()) также является объектом Worker.

В Django возможны три стиля наследования: Абстрактные базовые классы, Прокси-модели, и Многотабличное наследование

В этом случае вы используете Multi-Table Inheritance. Как следует из названия, каждая модель получает свою собственную таблицу в базе данных и, следовательно, может быть запрошена.

При запросе объектов Person в итоге вы получите экземпляры Person, а не экземпляры Worker или любого другого дочернего класса. Поскольку поле card_id определено не в модели Person, а в одной из ее дочерних моделей, вы получите ошибку при попытке получить значение card_id экземпляра Person, даже если этот экземпляр также является Worker.

Однако, если вы знаете, что ваш экземпляр Person также является Worker, вы можете получить его через:

person = Person.objects.all().first()
worker = person.worker

Это работает, поскольку отношения наследования создают OneToOneField между дочерним объектом и каждым из его родителей. Однако обратите внимание, что это приведет к ошибке в случае, если экземпляр person на самом деле не является Worker.

Одна библиотека, которая может помочь, это InheritanceManager из django-model-utils.

Присоединив InheritanceManager к модели вашего базового класса, например:

from model_utils.managers import InheritanceManager

class Person(models.Model):
    objects = InheritanceManager()
    # ...

Затем вы можете использовать фильтр .select_subclasses для фильтрации набора запросов родительской модели, чтобы включить только объекты определенного дочернего класса. Например, чтобы выбрать только лиц, которые также являются работниками, вы можете выполнить следующий запрос:

persons_worker = Person.objects.select_subclasses(Worker)

и вы никогда не столкнетесь с проблемами при попытке получить card_id для любого из экземпляров в persons_worker.

Вернуться на верх