我正在处理一个我没有开始的 Django 项目,我面临着继承问题。
我有一个大模型(在示例中进行了简化)MyModel
,它应该代表不同类型的项目。
的所有实例对象MyModel
都应具有相同的字段,但方法行为因项目类型而异。
到目前为止,它是使用一个MyModel
名为item_type
.
然后 MyModel 中定义的方法检查该字段并使用多个 if 执行不同的逻辑:
def example_method(self):
if self.item_type == TYPE_A:
do_this()
if self.item_type == TYPE_B1:
do_that()
更重要的是,一些子类型有很多共同点,所以我们说子类型B
和C
代表第一级继承。然后这些类型有子类型,例如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
如果我们已经知道我们正在处理的对象的类型,这可能会起作用。
假设我们要实例化 C1 类型的 MyModel 对象,那么我们可以简单地实例化 aModelC1
并且 item_type 将被正确设置。
问题是如何从通用 MyModel 实例中获取正确的代理模型?
最常见的情况是当我们得到一个查询集结果时:MyModel.objects.all()
所有这些对象都是 MyModel 的实例,它们对代理一无所知。
我见过不同的解决方案,比如 django-polymorphic,但据我所知,它依赖于多表继承,不是吗?
我见过的几个 SO 答案和自定义解决方案:
- https://stackoverflow.com/a/7526676/1191416
- Django中的多态性
- http://anthony-tresontani.github.io/Python/2012/09/11/django-polymorphism/
- https://github.com/craigds/django-typed-models
- 从基类创建 Django 代理模型的实例
但他们都没有100%说服我..
考虑到这可能是一种常见的情况,是否有人提出了更好的解决方案?