【问题标题】:How are many-to-many relationship handled in Django?Django中如何处理多对多关系?
【发布时间】:2021-01-28 20:45:53
【问题描述】:

我有一件可以包含多种颜色的衬衫,以及可以包含多种衬衫的多种颜色。通常我会用以下方式表达它:

在 django 我有多对多 (https://docs.djangoproject.com/en/3.1/topics/db/examples/many_to_many/) 示例:

publications = models.ManyToManyField(Publication)

-- 我可以创建包含 2 列(没有“ID”主键)的表“Item_colors”并使用复合键根据我的图表设计模型:

class Item_colors(models.Model):
    class Meta:
        unique_together = (('cloth_item_id', 'color_id'),)

    cloth_item_id = models.ForeignKey(Cloth_item, on_delete=models.CASCADE)
    color_id = models.ForeignKey(Color, on_delete=models.CASCADE)

在数据库上下文中如何处理多对多关系,它是否会产生更好的性能?

编辑:https://code.djangoproject.com/wiki/MultipleColumnPrimaryKeys 不避免使用主键来支持组合键保存列 :( 至少现在..

【问题讨论】:

  • A ManyToManyField 创建一个中间表,但有一个主键。在 Django 中,每个模型都有一个主键。
  • 谢谢 Willem,我假设中间表类似于我的“Item_colors”表?

标签: django postgresql django-models database-design relational-database


【解决方案1】:

在数据库上下文中如何处理多对多关系,它是否会产生更好的性能?

中间有一个连接表,所以有一个item_colors 表。但是该表包含一个主键,Django 中的每个模型也是如此。

如果你没有指定through=… parameter [Django-doc] 来自己定义联结表的模型,Django 会自动创建这样的模型。然后,此模型有两个 ForeignKeys 到它连接的两个模型,如database representation section of the documentation 中所述:

在幕后,Django 创建了一个中间连接表来表示多对多关系。默认情况下,此表名是使用多对多字段的名称和包含它的模型的表名生成的。由于某些数据库不支持超过一定长度的表名,这些表名将被自动截断并使用唯一性哈希,例如author_books_9cdf。您可以使用db_table 选项手动提供连接表的名称。

但是表因此有一个主键。如果同一对象在关系中第二次出现,这可能很有用。

您可以在Article-Publication 示例中访问直通模型,例如:

Article.publications<b>.through</b>

因此,您可以自己定义一个直通模型,例如:

class Color(models.Model):
    color = models.CharField(max_length=128)

class ClothItem(models.Model):
    item_name = models.CharField(max_length=128)
    colors = models.ManyToManyField(
        Color,
        related_name='cloth_items'
        through='ClothItemColors'
    )

class ClothItemColors(models.Model):
    cloth_item = models.ForeignKey(ClothItem, on_delete=models.CASCADE)
    color = models.ForeignKey(Color, on_delete=models.CASCADE)

    class Meta:
        db_table = 'item_colors'
        constraints = [
            models.UniqueConstraint(
                fields=('cloth_item', 'color'),
                name='unique_cloth_color'
            )
        ]

通常使用显式直通模型来存储额外信息,例如quantity

class ClothItemColors(models.Model):
    cloth_item = models.ForeignKey(ClothItem, on_delete=models.CASCADE)
    color = models.ForeignKey(Color, on_delete=models.CASCADE)
    quantity = models.IntegerField(default=0)

    # …

【讨论】:

  • 感谢 Willem,再次提供了很大的帮助 - 以及通过的很好的示例用法。我深入研究了您使用“UniqueConstraint”而不是我的“unique_together” - 文档同意:docs.djangoproject.com/en/3.1/ref/models/options/….. 我只是想念我可以避免保存列的表的主键,我有很多类似的表 :) 或者如果你说所有表都有一个主键(没有例外)
  • 我更新了原始问题,因为我找到了您的其他答案:stackoverflow.com/questions/61320317/… 和维基上的这个:code.djangoproject.com/wiki/MultipleColumnPrimaryKeys 没有避免主键支持复合键保存列:( 至少现在..
  • @LeOverflow:可悲的是,Django 的主键在其余代码中非常“硬连线”。例如DetailView 使用&lt;int:pk&gt; URL 路径参数自动过滤。很可能可以非常有效地在 Django 本身中实现更改,但是仍然存在依赖于一个主键的 Django 包的“生态系统”。所以我认为不要修复它,因为它可能会给其他包维护者带来很多工作。特别是对于有一段时间没有维护的包。
猜你喜欢
  • 2010-10-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-10-09
  • 2018-09-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多