Django 复杂关系
Posted
技术标签:
【中文标题】Django 复杂关系【英文标题】:Django complex relationship 【发布时间】:2016-01-14 10:47:00 【问题描述】:我有以下型号:
class A(models.Model):
title = models.CharField(max_length=30)
class B(models.Model):
title = models.CharField(max_length=255)
a = models.ManyToManyField(A)
我现在想要一个模型 C,它的字段具有 A 和 B 的多个唯一组合,例如 ManyToMany 字段。我发现可以使用将 ForeignKey 映射到两个模型 GenericForeignKey。我试过 GenericForeignKey 如下:
class C(models.Model):
title = models.CharField()
property1 = models.CharField()
a = models.ManyToManyField(A)
b = models.ManyToManyField(B)
a_b = GenericForeignKey(store, category)
但是,这似乎不起作用。有人可以指出我正确的方向吗?我是 Django 和 SQL 的新手。
编辑:阐明组合的要求。
Edit2:当前工作模型:
我创建了以下模型作为可行的解决方案:
class A(models.Model):
title = models.CharField(max_length=30)
class B(models.Model):
title = models.CharField(max_length=255)
a = models.ManyToManyField(A)
class C(models.Model):
title = models.CharField()
property1 = models.CharField()
class A_B_C(models.Model):
a = models.ForeignKey(A)
b = models.ForeignKey(B)
c = models.ForeignKey(C)
class Meta:
unique_together = ('a', 'b', 'c')
我避免在关系中显式创建和维护这个模型。我想知道这个解决方案是否有效或者是否有另一种 Django 方式来做事?
【问题讨论】:
【参考方案1】:当使用ManyToManyField
时,Django 会隐式地为您创建中间表。在您的示例中,您将获得包含(id, a_id, b_id)
列的附加表。但是您可以显式定义它并在B
模型上的字段a
上设置through
选项,然后为此中间模型定义unique_together
:
class A(models.Model):
title = models.CharField(max_length=30)
class B(models.Model):
title = models.CharField(max_length=255)
a = models.ManyToManyField(A, through='C')
class C(models.Model):
a = models.ForeignKey(A, on_delete=models.CASCADE)
b = models.ForeignKey(B, on_delete=models.CASCADE)
class Meta:
unique_together = ("a", "b")
注意:如果我没记错的话,你不能直接在ManyToManyFiled
上设置 unique_together。
【讨论】:
这行得通,但我也需要 a、b 的多种组合,就像在 ManyToMany 类型关系中一样。这里可以吗? 这是一个显式的多对多,但既然你写了 “我现在想要一个模型 C,它的字段是 A 和 B 的唯一组合。”它添加了一个唯一的约束。 上面写的代码,假设aN是A的实例,bN是B的实例,你可以有即:(a1-b1,a2-b1,a3-b1,a1-b2,a2- b2、a2-b3、a3-b1、a3-b2、a3-b3) 关系,这当然允许反向查找(感谢 Django ORM),即(b1-a1、b1-a2、b1-a3 等) .但是由于 unique_together,你不能拥有 (a1-b1, a1-b2, a2-b1, a2-b2, a1-b2)。 根据您的最后评论,我需要 a1-b1、a1-b2 可以映射到 c1。现在,c1 可以有 a1-b1 或 a1-b2。我已改进问题以包含此评论。 嗯,这是您在问题编辑中包含的解决方案之一。虽然由于您的 C 模型非常简单,但另一种方法是将 C 中的字段直接包含到 A_B_C,这是数据模型的非规范化,它会在查询时为您节省“连接”,但会占用更多存储空间,所以在此之前如果您真的需要,最好进行基准测试。【参考方案2】:这不是 GenericForeignKey 的工作。相反,您需要定义unique_together
Meta 属性:
class C(models.Model):
...
class Meta
unique_together = ('a', 'b')
【讨论】:
我试了一下,这里不允许使用 ManyToManyField。 试图了解你在这里真正需要什么。 A 和 B 已经通过 M2M 链接,为什么还需要两个额外的 M2M?你能在那种关系上寻找custom through table吗?【参考方案3】:供将来参考:
我创建了以下模型作为可行的解决方案:
class A(models.Model):
title = models.CharField(max_length=30)
class B(models.Model):
title = models.CharField(max_length=255)
a = models.ManyToManyField(A)
class C(models.Model):
title = models.CharField()
property1 = models.CharField()
class A_B_C(models.Model):
a = models.ForeignKey(A)
b = models.ForeignKey(B)
c = models.ForeignKey(C)
class Meta:
unique_together = ('a', 'b', 'c')
【讨论】:
以上是关于Django 复杂关系的主要内容,如果未能解决你的问题,请参考以下文章