При использовании типов 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
.