在多个参数filter和django中的链式filter之间的区别

django中有多个参数的filter和链式filter有什么区别?

正如您在生成的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') AND (entry__pub_date__year=2008) ,这是你期望从这个查询。

结果:

 Book with {entry.headline: 'Life of Lennon', 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)过滤。

不同的是它也会给你如下的结果:

预订

 {entry.headline: '**Lennon**', entry.pub_date: 2000}, {entry.headline: 'Bill', entry.pub_date: **2008**} 

一个表:但是如果查询不像Yuji和DTing的例子那样涉及到连接表。 结果是一样的。

大多数情况下,查询只有一个可能的结果集合。

链接filter的用法是在处理m2m时出现的:

考虑一下:

 # will return all Model with m2m field 1 Model.objects.filter(m2m_field=1) # will return Model with both 1 AND 2 Model.objects.filter(m2m_field=1).filter(m2m_field=2) # this will NOT work Model.objects.filter(Q(m2m_field=1) & Q(m2m_field=2)) 

其他例子欢迎。

“multiple arguments filter-query”的结果不同于“chained-filter-query”的情况如下:

在引用对象和关系的基础上select引用对象是一对多(或多对多)。

多个filter:

  Referenced.filter(referencing1_a=x, referencing1_b=y) # same referencing model ^^ ^^ 

链式filter:

  Referenced.filter(referencing1_a=x).filter(referencing1_b=y) 

两个查询都能输出不同的结果:
如果引用模型Referencing1多于一行可以引用参考模型Referencing1中的同一行。 在Referenced可以是这种情况: Referencing1具有1:N(一对多)或N:M(多对多)的关系。

例:

考虑我的应用my_company有两个模型EmployeeDependentmy_company的员工可以有更多的受抚养人(换句话说,受抚养人可以是单个雇员的儿子/女儿,而雇员可以有一个以上的儿子/女儿)。
呃,假设夫妻双方都不能在my_company工作。 我拿了1:m的例子

所以, Employee是被引用的模型,可以被更多的引用模型引用。 现在考虑关系状态如下:

 Employee: Dependent: +------+ +------+--------+-------------+--------------+ | name | | name | E-name | school_mark | college_mark | +------+ +------+--------+-------------+--------------+ | A | | a1 | A | 79 | 81 | | B | | b1 | B | 80 | 60 | +------+ | b2 | B | 68 | 86 | +------+--------+-------------+--------------+ 

从属a1是指员工A ,依赖b1, b2指员工B

现在我的查询是:

find所有员工在学校和学校有儿子/女儿都有区别标记(> = 75%)?

 >>> Employee.objects.filter(dependent__school_mark__gte=75, ... dependent__college_mark__gte=75) [<Employee: A>] 

输出是“A”,依赖于“a1”在学院和学校都有区分标记,这取决于员工“A”。 注意'B'没有被选中,因为'B'的孩子在学院和学校都有分别的标记。 关系代数:

员工⋈(school_mark> = 75且college_mark> = 75)受抚养人

其次,我需要一个查询:

find一些家属在学校和学校都有区分标记的所有员工?

 >>> Employee.objects.filter( ... dependent__school_mark__gte=75 ... ).filter( ... dependent__college_mark__gte=75) [<Employee: A>, <Employee: B>] 

这次'B'也是因为'B'有两个孩子(不止一个!),一个在学校有'b1'而另一个在大学'b2'有区别标记。
过滤顺序并不重要,我们也可以把上面的查询写成:

 >>> Employee.objects.filter( ... dependent__college_mark__gte=75 ... ).filter( ... dependent__school_mark__gte=75) [<Employee: A>, <Employee: B>] 

结果是一样的! 关系代数可以是:

(员工⋈(school_mark> = 75)受抚养人) (college_mark> = 75)受抚养人

注意如下:

 dq1 = Dependent.objects.filter(college_mark__gte=75, school_mark__gte=75) dq2 = Dependent.objects.filter(college_mark__gte=75).filter(school_mark__gte=75) 

输出相同的结果: [<Dependent: a1>]

我使用print qd1.queryprint qd2.query检查由Django生成的目标SQL查询是否相同(Django 1.6)。

但是语义上两者都不同于 。 第一个看起来像是简单的部分σ [school_mark> = 75 AND college_mark> = 75] (从属),其次是慢嵌套查询:σ [school_mark> = 75] (σ [college_mark> = 75] (Dependent))。

如果你需要Code @codepad

顺便说一句,这是在文档@ 跨越多值关系给我刚刚添加了一个例子,我认为这将有助于一个新的。

您可以使用连接模块查看要比较的原始sql查询。 正如Yuji所解释的那样,它们大部分是相同的,如下所示:

 >>> from django.db import connection >>> samples1 = Unit.objects.filter(color="orange", volume=None) >>> samples2 = Unit.objects.filter(color="orange").filter(volume=None) >>> list(samples1) [] >>> list(samples2) [] >>> for q in connection.queries: ... print q['sql'] ... SELECT `samples_unit`.`id`, `samples_unit`.`color`, `samples_unit`.`volume` FROM `samples_unit` WHERE (`samples_unit`.`color` = orange AND `samples_unit`.`volume` IS NULL) SELECT `samples_unit`.`id`, `samples_unit`.`color`, `samples_unit`.`volume` FROM `samples_unit` WHERE (`samples_unit`.`color` = orange AND `samples_unit`.`volume` IS NULL) >>> 

性能差异是巨大的。 试试看看。

Model.objects.filter(condition_a).filter(condition_b).filter(condition_c)

相比之下是惊人的慢

Model.objects.filter(condition_a, condition_b, condition_c)

正如“Effective Django ORM”中所提到的,

  • QuerySets在内存中维护状态
  • 链接触发克隆,复制该状态
  • 不幸的是,QuerySets保持了很多状态
  • 如果可能的话,不要链接多个filter

如果你最终在这个页面上寻找如何使用多个链接filter来dynamic构build一个Django查询集,但是你需要filter是ANDtypes而不是OR ,那么考虑使用Q对象 。

一个例子:

 # First filter by type. filters = None if param in CARS: objects = app.models.Car.objects filters = Q(tire=param) elif param in PLANES: objects = app.models.Plane.objects filters = Q(wing=param) # Now filter by location. if location == 'France': filters = filters & Q(quay=location) elif location == 'England': filters = filters & Q(harbor=location) # Finally, generate the actual queryset queryset = objects.filter(filters) 

例如,当您向相关对象发出请求时,就会有所不同

 class Book(models.Model): author = models.ForeignKey(Author) name = models.ForeignKey(Region) class Author(models.Model): name = models.ForeignKey(Region) 

请求

 Author.objects.filter(book_name='name1',book_name='name2') 

返回空集

并要求

 Author.objects.filter(book_name='name1').filter(book_name='name2') 

返回具有“name1”和“name2”两种书籍的作者

有关详细信息, 请参阅https://docs.djangoproject.com/en/dev/topics/db/queries/#s-spanning-multi-valued-relationships