Я работаю над проектом Django, который я не запустил, и столкнулся с проблемой наследования .
У меня есть большая модель (упрощенная в примере), которая называется MyModel
, котораядолжен представлять различные типы элементов.
Все объекты экземпляра MyModel
должны иметь одинаковые поля, но поведение методов сильно различается в зависимости от типа элемента.
До этогов тот момент, когда это было разработано с использованием одного поля MyModel
с именем item_type
.
Затем методы, определенные в MyModel, проверяют это поле и выполняют другую логику, используя множественные выражения, если:
def example_method(self):
if self.item_type == TYPE_A:
do_this()
if self.item_type == TYPE_B1:
do_that()
Ещеиз подтипов есть много общего, поэтому, скажем, подтипы B
и C
представляют 1-й уровень наследования.Тогда эти типы имеют подтипы, например, B1
, B2
, C1
, C2
(лучше объяснено в примере кода ниже).
Я бы сказал, что это не лучший подход для выполнения полиморфизма.
Теперь я хочу изменить эти модели для использования реального наследования.
Поскольку все подмодели имеют одинаковые поля, я думаю, что наследование нескольких таблиц не является необходимым.Я думал об использовании моделей прокси , потому что только их поведение должно меняться в зависимости от их типов.
Это псевдо-решение, к которому я пришел:
ITEM_TYPE_CHOICES = (
(TYPE_A, _('Type A')),
(TYPE_B1, _('Type B1')),
(TYPE_B2, _('Type B2')),
(TYPE_C1, _('Type C1')),
(TYPE_C2, _('Type C2')))
class MyModel(models.Model):
item_type = models.CharField(max_length=12, choices=ITEM_TYPE_CHOICES)
def common_thing(self):
pass
def do_something(self):
pass
class ModelA(MyModel):
class Meta:
proxy = True
def __init__(self, *args, **kwargs):
super().__init__(self, *args, **kwargs)
self.item_type = TYPE_A
def do_something(self):
return 'Hola'
class ModelB(MyModel):
class Meta:
proxy = True
def common_thing(self):
pass
class ModelB1(ModelB):
class Meta:
proxy = True
def __init__(self, *args, **kwargs):
super().__init__(self, *args, **kwargs)
self.item_type = TYPE_B1
def do_something(self):
pass
class ModelB2(ModelB):
class Meta:
proxy = True
def __init__(self, *args, **kwargs):
super().__init__(self, *args, **kwargs)
self.item_type = TYPE_B2
def do_something(self):
pass
Этоможет сработать, если мы уже знаем тип объекта, над которым мы работаем.
Допустим, мы хотим создать экземпляр объекта MyModel типа C1, тогда мы могли бы просто создать экземпляр ModelC1
, и item_type будет настроен правильно.
Проблема в том, как получить правильную модель прокси из общих экземпляров MyModel?
Наиболее распространенный случай - когда мы получаем результат набора запросов: MyModel.objects.all()
, все эти объекты являются экземплярами MyModelи они ничего не знают о прокси.
Я видел разные решения, такие как django-polymorphic , но, как я понял, это основано на наследовании нескольких таблиц, не так ли?не так ли?
Несколько SO ответов и пользовательских решений, которые я видел:
, но никто из них не убедил меня на 100% ..
Учитывая, что это может быть распространенным сценарием, кто-нибудь придумал лучшее решение?