Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/django/20.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python Django中的多态模型遗传_Python_Django_Inheritance_Django Models_Sqlalchemy - Fatal编程技术网

Python Django中的多态模型遗传

Python Django中的多态模型遗传,python,django,inheritance,django-models,sqlalchemy,Python,Django,Inheritance,Django Models,Sqlalchemy,这个问题是关于Django中的模型继承的 我读过的几乎所有内容(包括Django文档本身)都强烈建议执行'abstract base class'继承,而不是'multi-table'继承。 我同意这个理由,因此我完全支持这项建议。然而,Django没有这样做 似乎支持: 多态查询,或 模型链接(即,我无法从另一个模型创建指向抽象基类的ForeignKey字段) 处境 例如,我有一些实现“抽象基类”继承模式的模型: class Tool(models.Model): name = m

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

我读过的几乎所有内容(包括Django文档本身)都强烈建议执行'abstract base class'继承,而不是'multi-table'继承。 我同意这个理由,因此我完全支持这项建议。然而,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, null=True, 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和Hibernate等其他ORM中是可能的

对于Django ORM,由于
工具
类是抽象的,因此我无法创建如下链接:

  • toolbattributevalue.tool->tool_obj
  • ToolGroup.tools->[tool_obj_1,tool_obj_2]
相反,我被迫在抽象类上创建反向链接,尽管它建模了一个稍微不同的东西!这会导致
ToolAttributeValue
ToolGroup
对象上出现各种各样的丑陋,这些对象不再具有
.tools
属性,而是具有每个子类型的
RelatedManager
字段。i、 e:

tool_group_obj.handheldtool_set.all()
tool_group_obj.powertool_set.all()
...etc, for every subtype of Tool
这几乎破坏了抽象类的实用性

问题 因此,考虑到这一点,我的问题是:

  • 这是“多表”继承的好例子吗
  • 我是不是太想强制类型继承了?我应该扔掉
    工具吗?如果是,那么我是否必须为每个子类创建
    *工具组
    模型
  • 目前(Django 1.8)接受的解决方法是什么?我肯定不是第一个在Django建立关系系统的人;-)其他orm也考虑了这个问题,这表明它是一种常见的设计选择
  • 多态解决方案(可能通过SQLAlchemy)是一种选择吗?Django 1.9+是否考虑使用此功能
  • 注:我已经阅读了很多文档并进行了测试,但它似乎不起作用 对于“抽象基类”继承(即,它仅适用于多表)。如果我选择了多表继承,那么 django多态将有助于解决我的问题的查询方面,我想我的模型链接问题将消失


    注:这是一个与类似的问题,但提供了更多细节。

    好的,所以我想我将回答我自己的问题

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

    看来是这样。尽管有一些地方建议不要使用“多表”继承(),但也有一些反对意见:

    • @Bruno Desthuilliers指出,这些观点并非来自“官方”文档,因此,他暗示“多表”是一个非常好的功能,可供一个人使用

    • 我对@dhke的链接和评论的理解是,您必须选择一个选项,“多表”选项是数据库真正支持继承的唯一方式。也就是说,即使使用Hibernate或SQLAlchemy等工具的多态技巧,您仍然可以选择是连接表(“多表”选项)进行对象查找,还是联合表(“抽象基”/“多态”选项)进行集合创建

    • @dhke还指出,最好使用“multi table”选项,并告诉类库在查找“整集”时不要进行子类解析,而不是让数据库对所有表进行并集(使用“抽象基类”选项进行“整集”查找时需要这样做)

  • 我是否太过努力地强制执行类型继承?我应该扔掉
    工具吗?如果是,那么我是否必须为每个子类创建
    *工具组
    模型?

    不,看起来不是那样的。我介绍的
    工具
    界面的两种用途有不同的需求:

    • 工具组
      /分层分组用例是保留继承的
      工具
      类的好用例。如果您必须为每种类型的工具创建一组特定于类型的类,那么这将变得非常糟糕

    • toolbattribute
      也为超类提供了一个很好的例子,除非您能够使用诸如HSTORE字段类型(由Postgres提供,我不确定是否有其他后端)。给出了一个很好的概述,这可能就是我在这里要做的(感谢@nigel222对这个问题的研究!)

  • 目前(Django 1.8)接受的解决方法是什么?我肯定不是第一个在Django建立关系系统的人;-)其他ORM也考虑了这个问题,这表明这是一种常见的设计选择。

    这现在是一个无关紧要的问题。基本上他们不担心

  • 多态解决方案(可能通过SQLAlchemy)是一种选择吗?Django 1.9+是否考虑使用此功能?

    我看不出来


  • 导致我提出这个问题的案例是这样一个模型:

    class PurchasableItem(models.Model):
    
        class Meta:
            abstract = True
    
    
    class Cheesecake(PurchasableItem):
        pass
    
    
    class Coffee(PurchasableItem):
        pass
    
    我使用的解决方法是将父类转换为属性:

    class PurchasableItem(models.Model):
    
        class Meta:
            abstract = False
    
    
    class Cheesecake(models.Model):
        purchasable_item = models.OneToOneField(PurchasableItem, on_delete=models.CASCADE)
    
    
    class Coffee(models.Model):
        purchasable_item = models.OneToOneField(PurchasableItem, on_delete=models.CASCADE)
    
    这样,我可以同时获得行为和查询功能。

    好吧,选择
    abstract=True
    避免了基表联接,但您也选择了根本不能拥有基模型的in-db表示(这意味着您也不能查询抽象模型)
    abstract=True
    本质上意味着不实现这个模型,它只是