python – Django中的多态模型继承

这个问题是关于Django中的模型继承.几乎所有我读过的内容(包括Django文档本身)都强烈建议使用“抽象基类”继承而不是“多表”继承.我同意推理,因此完全支持这项建议.但是,Django没有似乎有支持:多态查询,或模型链接(即我不能从另一个模型创建一个ForeignKey

这个问题是关于Django中的模型继承.

几乎所有我读过的内容(包括Django文档本身)都强烈建议使用“抽象基类”继承而不是“多表”继承.
我同意推理,因此完全支持这项建议.但是,Django没有
似乎有支持:

>多态查询,或
>模型链接(即我不能从另一个模型创建一个ForeignKey字段到抽象基类).

情况

例如,我有一些实现’抽象基类’继承模式的模型:

class Tool(models.Model):
    name = models.CharField(max_length=30)
    group = models.ManyToManyField(ToolGroup,blank=True) # Link to 'ToolGroup' MUST be placed on abstract class
    attributes = models.ManyToManyField(ToolAttributeValue,blank=True)  # Link to 'ToolAttributeValue' MUST be placed on abstract class

    class Meta:
        abstract = True # Almost everything I read strongly recommends against making this its own table


class HandheldTool(Tool):
    electrical_safe = models.BooleanField(default=False)


class PowerTool(Tool):
    compliance_expiry_date = models.DateTimeField()


class ConsumableTool(Tool):
    combustible = models.BooleanField(default=False)
    best_before = models.DateTimeField(null=True)

我还有一些与工具相关的分组和信息类:

# Grouping related structures
#
# ToolHierarchy  >       ToolGroup (n times)       > Tool
# 
#   "Tool Boxes" > "Day Shift"   > "Builders"      > HandheldTool[Hammer]
#                                                  > HandheldTool[Screwdriver - SAFE]
#                                                  > PowerTool[Drill]
#
#                                > "Demo Team"     > HandheldTool[Sledgehammer 1]
#                                                  > PowerTool[Jackhammer]
#                                                  > ConsumableTool[Dynamite]
#
#                > "Night Shift" > "Rock Breakers" > HandheldTool[Hammer]
#                                                  > HandheldTool[Sledgehammer 2]
#                                                  > PowerTool[Rocksaw]

class ToolHierarchy(models.Model):
    name = models.CharField(blank=True,max_length=30)


class ToolGroup(models.Model):
    name = models.CharField(blank=True,max_length=30)
    parent = models.ForeignKey('self',related_name='children',null=True,blank=True)
    hierarchy = models.ForeignKey(ToolHierarchy,blank=True,related_name='top_level_tools')
    # tools = models.ManyToManyField(Tool) # CANNOT MAKE LINK,as 'Tool' is abstract


# 'Extra-info' structures
#
# ToolAttribute > ToolAttributeValue > Tool
# 
#  'Brand'      > 'Stanley'          > HandheldTool[Hammer]
#                                    > HandheldTool[Sledgehammer 1]
#               > 'ACME'             > HandheldTool[Sledgehammer 2]
#                                    > ConsumableTool[Dynamite]
#
#  'Supplier'   > 'Bash Brothers'    > HandheldTool[Hammer]
#                                    > HandheldTool[Sledgehammer 1]
#                                    > HandheldTool[Sledgehammer 2]
class ToolAttribute(models.Model):
    name = models.CharField(max_length=30)
    data_type = models.CharField(max_length=30) # e.g. "STRING","INT","DATE" "FLOAT" -- Actually done with enum
    unit_of_measure = models.CharField(max_length=30,blank=True)


class ToolAttributeValue(models.Model):
    attribute = models.ForeignKey(ToolAttribute)
    value = models.CharField(blank=True,max_length=30)
    # tool = models.ForeignKey(Tool)  # CANNOT MAKE LINK,as 'Tool' is abstract

问题

理想情况下,这种继承模型将通过多态关系实现,但Django ORM不会
支持它.这可以通过SQLAlchemy和其他ORM(如Hibernate)实现.

使用Django ORM,因为Tool类是抽象的,所以无法创建如下链接:

> ToolAttributeValue.tool – > tool_obj或
> ToolGroup.tools – > [tool_obj_1,tool_obj_2].

相反,我被迫在抽象类上创建反向链接,尽管它模拟了一个稍微不同的东西!然后,这会在ToolAttributeValue和ToolGroup对象上产生各种丑陋,然后不再具有.tools属性,而是为每个子类型提供RelatedManager字段.即:

tool_group_obj.handheldtool_set.all()
tool_group_obj.powertool_set.all()
...etc,for every subtype of Tool

这几乎破坏了抽象类的有用性.

问题

所以,考虑到这一点,我的问题是:

>这是“多表”继承的好例子吗?
>我是否努力强迫类型继承?我应该摆脱工具吗?如果是,那么我是否必须为每个子类创建一个* ToolGroup模型?
>目前(Django 1.8)接受的方式是什么?当然,我不是第一个在Django中建立关系系统的人;-)而且其他ORM考虑过这个问题的事实表明它是一种常见的设计选择.
>多态解决方案(可能通过SQLAlchemy)是一个选项吗?这是否被考虑用于Django 1.9?

注意:我已经阅读了文档并测试了https://github.com/chrisglass/django_polymorphic,但它似乎不起作用
用于’抽象基类’继承(即它仅用于多表).如果我确实选择了多表继承那么
django-polymorphic对我的问题的查询方面有好处,我猜我的模型链接问题会消失.

注意:这是与this one类似的问题,但提供了更多细节.
最佳答案
好的,所以我想我会回答我自己的问题……

>这是“多表”继承的好例子吗?

它看起来如此.虽然有一些地方建议不要使用“多表”继承(listed here for example),但有些反对意见是:

> @Bruno Desthuilliers指出,这些意见并非来自“官方”文档,而且,通过扩展,他暗示“多表”是一个非常好的功能供一个人使用.
>我读@dhke的链接和注释是你必须选择一个选项,’多表’选项是数据库真正支持继承的唯一方法.即即使使用Hibernate或SQLAlchemy等工具的多态技巧,您仍然选择是否为对象查找加入表(‘multi-table’选项),或者为集合创建选择UNION表(‘abstract base’/’polymorphic’选项).
> @dhke还指出,使用’multi-table’选项可能更好,并告诉像django-polymorphic这样的库在查找’整集’时不要做子类解析,而不是让数据库对整个数据库执行UNION表(使用’abstract base class’选项进行’整集’查找所需的表).

>我是否努力强迫类型继承?我应该摆脱工具吗?如果是,那么我是否必须为每个子类创建一个* ToolGroup模型?

不,它似乎不是那样的.我提供的Tool界面的两种用法有不同的需求:

> ToolGroup / hierarchical-grouping用例是保留继承的Tool类的好用例.如果必须为每种类型的工具创建特定于类型的类集,这将变得非常难看
> ToolAttribute也为超类提供了一个很好的例子,除非你能够使用HSTORE字段类型之类的东西(由Postgres提供,我不确定其他后端). This link给出了一个很好的纲要,这可能就是我将在这里做的(感谢@ nigel222进行了研究的问题!).

>目前(Django 1.8)接受的方式是什么?当然,我不是第一个在Django中建立关系系统的人;-)而且其他ORM考虑过这个问题的事实表明它是一种常见的设计选择.

现在这是一个无关紧要的问题.基本上他们不担心.
>多态解决方案(可能通过SQLAlchemy)是一个选项吗?这是否被考虑用于Django 1.9?

不是我能说出来的.

作者: dawei

【声明】:永州站长网内容转载自互联网,其相关言论仅代表作者个人观点绝非权威,不代表本站立场。如您发现内容存在版权问题,请提交相关链接至邮箱:bqsm@foxmail.com,我们将及时予以处理。

为您推荐

联系我们

联系我们

0577-28828765

在线咨询: QQ交谈

邮箱: xwei067@foxmail.com

工作时间:周一至周五,9:00-17:30,节假日休息

返回顶部