在Django中链接多个filter(),这是一个错误?

我总是认为在Django中链接多个filter()调用总是和在一次调用中收集它们一样。

# Equivalent Model.objects.filter(foo=1).filter(bar=2) Model.objects.filter(foo=1,bar=2) 

但我已经在我的代码中运行了一个复杂的查询集,但事实并非如此

 class Inventory(models.Model): book = models.ForeignKey(Book) class Profile(models.Model): user = models.OneToOneField(auth.models.User) vacation = models.BooleanField() country = models.CharField(max_length=30) # Not Equivalent! Book.objects.filter(inventory__user__profile__vacation=False).filter(inventory__user__profile__country='BR') Book.objects.filter(inventory__user__profile__vacation=False, inventory__user__profile__country='BR') 

生成的SQL是

 SELECT "library_book"."id", "library_book"."asin", "library_book"."added", "library_book"."updated" FROM "library_book" INNER JOIN "library_inventory" ON ("library_book"."id" = "library_inventory"."book_id") INNER JOIN "auth_user" ON ("library_inventory"."user_id" = "auth_user"."id") INNER JOIN "library_profile" ON ("auth_user"."id" = "library_profile"."user_id") INNER JOIN "library_inventory" T5 ON ("library_book"."id" = T5."book_id") INNER JOIN "auth_user" T6 ON (T5."user_id" = T6."id") INNER JOIN "library_profile" T7 ON (T6."id" = T7."user_id") WHERE ("library_profile"."vacation" = False AND T7."country" = BR ) SELECT "library_book"."id", "library_book"."asin", "library_book"."added", "library_book"."updated" FROM "library_book" INNER JOIN "library_inventory" ON ("library_book"."id" = "library_inventory"."book_id") INNER JOIN "auth_user" ON ("library_inventory"."user_id" = "auth_user"."id") INNER JOIN "library_profile" ON ("auth_user"."id" = "library_profile"."user_id") WHERE ("library_profile"."vacation" = False AND "library_profile"."country" = BR ) 

带链式filter()调用的第一个查询集连接库存模型两次,有效地在两个条件之间创build一个“或”,而第二个查询集将这两个条件同时存储在一起。 我期待第一个查询也会和这两个条件。 这是预期的行为还是这是一个在Django中的错误?

相关问题的答案在Django中使用“.filter()。filter()。filter()…”有什么不好的地方? 似乎表明这两个查询集应该是等价的。

我的理解是,他们是微妙的不同devise(我当然​​可以打开纠正): filter(A, B)将首先根据A筛选,然后根据B filter(A).filter(B) ,同时filter(A).filter(B)将返回与A'匹配的行和'与B匹配的可能不同的行。

看看这里的例子:

https://docs.djangoproject.com/en/dev/topics/db/queries/#spanning-multi-valued-relationships

尤其:

同时应用单个filter()调用中的所有内容,以筛选出满足所有这些要求的项目。 连续的filter()调用进一步限制了对象的集合

在第二个例子中(filter(A).filter(B)),第一个filter限制查询集为(A)。 第二个filter将博客集进一步限制为那些也是(B)的博客。 由第二个filterselect的条目可能与第一个filter中的条目相同或不同

在大多数情况下,这两种筛选方式是等价的,但是当基于ForeignKey或ManyToManyField查询对象时,它们稍有不同。

文档中的示例

模型
Blog to Entry是一对多的关系。

 from django.db import models class Blog(models.Model): ... class Entry(models.Model): blog = models.ForeignKey(Blog) headline = models.CharField(max_length=255) pub_date = models.DateField() ... 

对象
假设这里有一些博客和入口对象。
在这里输入图像描述

查询

 Blog.objects.filter(entry__headline_contains='Lennon', entry__pub_date__year=2008) Blog.objects.filter(entry__headline_contains='Lennon').filter( entry__pub_date__year=2008) 

对于第一个查询(单个filter),它只匹配blog1。

对于第二个查询(链接filter之一),它将过滤掉blog1和blog2。
第一个filter将查询集限制为blog1,blog2和blog5; 第二个filter将这组博客进一步限制为blog1和blog2。

你应该意识到这一点

我们使用每个filter语句过滤Blog项目,而不是Entry项目。

所以,这是不一样的,因为Blog和Entry是多值关系。

参考: https : //docs.djangoproject.com/en/1.8/topics/db/queries/#spanning-multi-valued-relationships
如果有什么问题,请纠正我。

编辑:由于1.6链接不再可用,将v1.6更改为v1.8。

正如您在生成的SQL语句中所看到的,不同之处不在于某些人可能怀疑的“或”。 这是如何放置WHERE和JOIN。

示例1(相同的连接表):

https://docs.djangoproject.com/en/dev/topics/db/queries/#spanning-multi-valued-relationships中的示例);

 Blog.objects.filter(entry__headline__contains='Lennon', entry__pub_date__year=2008) 

这将给你所有的博客有一个条目(entry_ headline _contains ='Lennon')和(entry__pub_date__year = 2008),这是你期望从这个查询。 结果:预订{entry.headline:'列侬生活',entry.pub_date:'2008'}

示例2(链接)

 Blog.objects.filter(entry__headline__contains='Lennon').filter(entry__pub_date__year=2008) 

这将涵盖示例1的所有结果,但会产生稍微更多的结果。 因为它首先使用(entry_ headline _contains ='Lennon')过滤所有博客,然后从结果filter(entry__pub_date__year = 2008)中过滤。

不同的是,它也会给你如下结果:Book with {entry.headline:' Lennon ',entry.pub_date:2000},{entry.headline:'Bill',entry.pub_date: 2008 }

在你的情况

我认为这是你需要的一个:

 Book.objects.filter(inventory__user__profile__vacation=False, inventory__user__profile__country='BR') 

如果你想使用或请阅读: https : //docs.djangoproject.com/en/dev/topics/db/queries/#complex-lookups-with-q-objects