Django ORM处理多个多对多关系的方法

9 投票
2 回答
6143 浏览
提问于 2025-04-16 11:50

亲爱的帮助他人的朋友们,

我正在尝试弄明白如何在Django中进行连接,而不需要写自定义的SQL语句。

假设我有以下模型:

class Parent(models.Model): 
  name =  models.CharField()
  children = models.ManyToManyField(Child, through="Parent_Child", related_name="parents")

class Parent_Child(models.Model):
  parent = models.ForeignKey(Parent, related_name='attached_children')
  child = models.ForeignKey(Child,  related_name='attached_parents')

class Child(models.Model): 
  name = models.CharField() 
  toys = models.ManyToManyField(Toy, hrough="Child_Toy", related_name="toy_owners")

class Child_Toy(models.Model): 
  child = models.ForeignKey(Child, related_name='attached_toys') 
  toy =  models.ForeignKey(Toy, related_name='toy_owner')

class Toy(models.Model): 
  name = models.CharField

一个父母可以有多个孩子,而一个孩子也可以有多个父母。一个孩子可以拥有多个玩具,而玩具也可以被多个孩子拥有。

我想要获取一个父母的孩子们所拥有的所有玩具的列表。

所以,我可以做一些像这样的操作: parent.children.all()child.toys.all()

我想要做的事情是像这样 parent.children.toys.all()。当我尝试这样做时,我得到了:AttributeError: 'ManyRelatedManager' object has no attribute 'toys'。我明白这个错误的意思——parent.children 返回了多个记录,这是正常的。但我搞不清楚的是,如何告诉Django我想在查询中添加一个额外的连接。

有没有办法在Django中实现这个连接,还是说我必须使用自定义的SQL才能做到这一点?

请注意:以上内容只是为了说明我的问题,实际上我使用的模型并不是那么重要。我的问题主要是想弄清楚如何在Django中通过多个多对多关系进行连接,而不需要使用SQL。

提前感谢你的帮助。谢谢!

2 个回答

5

如果你在中间表 Parent_ChildChild_Toy 中不存储额外的信息,你可以直接不使用它们——Django会自动为你创建这些表。所以一个简化的设置看起来会是这样的:

class Parent(models.Model): 
    name =  models.CharField(max_length=80)
    children = models.ManyToManyField('Child', related_name="parent")

class Child(models.Model): 
    name = models.CharField(max_length=80) 
    toys = models.ManyToManyField('Toy', related_name="owner")

class Toy(models.Model): 
    name = models.CharField(max_length=80)

你可以通过使用 字段查找 来查询特定父母的玩具。

Toy.objects.filter(owner__parent__id=1)

或者:

Toy.objects.filter(owner__parent=parent)

生成的 SQL 看起来大概是这样的:

SELECT "toy"."id", "toy"."name" FROM "toy" 
    INNER JOIN "child_toys"
        ON ("toy"."id" = "child_toys"."toy_id") 
    INNER JOIN "child"
        ON ("child_toys"."child_id" = "child"."id") 
    INNER JOIN "parent_children" 
        ON ("child"."id" = "parent_children"."child_id")
    WHERE "parent_children"."parent_id" = 1
9

简单地写点像这样的代码:

Toy.objects.filter(toy_owners__parents=parent)

撰写回答