Django ORM经历多个多对多关系的方式

时间:2011-02-15 03:15:49

标签: python django

亲爱的人们试图帮助他人,

我试图找出如何让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中通过多个M2M关系加入,而不必诉诸SQL。

我提前感谢您的帮助。谢谢!

2 个答案:

答案 0 :(得分:7)

简单地写一下:

Toy.objects.filter(toy_owners__parents=parent)

答案 1 :(得分:2)

如果您不在中间表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)

您可以使用field lookups查询特定父母的玩具。

Toy.objects.filter(owner__parent__id=1)

或者:

Toy.objects.filter(owner__parent=parent)

resulting 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