Django 代理模型的继承和多态性

Leo*_*rdo 7 python django proxy-classes django-models django-inheritance

我正在开发一个我没有启动的 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()
Run Code Online (Sandbox Code Playgroud)

更重要的是,某些子类型有许多共同点,因此可以说子类型BC代表第一级继承。然后这些类型有子类型,例如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
Run Code Online (Sandbox Code Playgroud)

如果我们已经知道我们正在处理的对象的类型,这可能会起作用。
假设我们想要实例化一个类型为 C1 的 MyModel 对象,那么我们可以简单地实例化 aModelC1并且 item_type 将被正确设置。

问题是如何从通用的 MyModel 实例中获取正确的代理模型?

最常见的情况是当我们获得查询集结果:时MyModel.objects.all(),所有这些对象都是 MyModel 的实例,并且它们对代理一无所知。

我见过不同的解决方案,例如 django-polymorphic,但据我了解,它依赖于多表继承,不是吗?

我见过的几个SO答案和自定义解决方案:

但他们都没有100%说服我..

考虑到这可能是一种常见的情况,有人想出了更好的解决方案吗?

bru*_*ers 0

我对模型代理的经验很少,所以我无法判断这是否可以正常工作(没有任何我的意思),也不知道这可能有多复杂,但是您可以使用映射item_type:ProxyClass并覆盖模型的查询集(或提供第二个管理器自定义查询集等)实际查找此映射并实例化正确的代理模型。

顺便说一句,您可能需要 at django.models.base.Model.from_db,它(快速浏览一下源代码)似乎是QuerySet.populate()实例化模型所调用的方法。只需重写此方法可能就足以解决问题 - 但这里它也可能会破坏某些东西......