Django 如何处理多对多关系?

How are many-to-many relationship handled in Django?

我有一件可以包含多种颜色的衬衫,以及可以包含多件衬衫的多种颜色。通常我会这样表达:

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

publications = models.ManyToManyField(Publication)

-- 我可以创建由 2 列(无“ID”主键)组成的 table“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 不避免主键以支持复合键保存列 :( 至少现在..

How is the many-to-many relation handled in a DB context, and does it yield better performance?

中间有一个交叉点 table,所以有一个 item_colors table。但是 table 包含一个主键,就像 Django 中的每个模型一样。

如果不指定through=… parameter [Django-doc] to define the model for the junction table yourself, Django will automatically create such model. This model then has two ForeignKeys to the two models it connects as discussed in the database representation section of the documentation:

Behind the scenes, Django creates an intermediary join table to represent the many-to-many relationship. By default, this table name is generated using the name of the many-to-many field and the name of the table for the model that contains it. Since some databases don’t support table names above a certain length, these table names will be automatically truncated and a uniqueness hash will be used, e.g. author_books_9cdf. You can manually provide the name of the join table using the db_table option.

但是 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)
    <b>quantity</b> = models.IntegerField(default=0)

    # …