django中有多个参数的过滤器和链过滤器有什么区别?
答案 0 :(得分:42)
正如您在生成的SQL语句中看到的那样,差异不是" OR"有些人可能会怀疑。这是WHERE和JOIN的放置方式。
Example1(相同的连接表):来自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)
的一个条目的所有博客,这是您对此查询的期望。
结果:
Blog 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')
过滤所有博客,然后从结果过滤器(entry__pub_date__year=2008)
过滤。
不同之处在于它还会为您提供如下结果:
包含多个条目的单个博客
{entry.headline: '**Lennon**', entry.pub_date: 2000},
{entry.headline: 'Bill', entry.pub_date: **2008**}
当评估第一个过滤器时,由于第一个条目而包含书籍(即使它有其他不匹配的条目)。当评估第二个过滤器时,由于第二个条目,包括书。
一个表格但是如果查询不涉及连接表,例如来自Yuji和DTing的示例。结果是一样的。
答案 1 :(得分:15)
大多数情况下,查询只有一组可能的结果。
当您处理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))
欢迎其他例子。
答案 2 :(得分:13)
“多个参数filter-query”的结果与“chained-filter-query”不同的情况,如下:
根据引用对象和关系选择引用的对象是一对多(或多对多)。
多个过滤器:
Referenced.filter(referencing1_a=x, referencing1_b=y) # same referencing model ^^ ^^
链式过滤器:
Referenced.filter(referencing1_a=x).filter(referencing1_b=y)
两个查询都可以输出不同的结果:
如果超过一个 引用模型Referencing1
中的行可以引用同一行 引用的模型Referenced
。这可能是Referenced
中的情况:Referencing1
有1:N(一对多)或N:M(多对多) 关系船
示例:
考虑我的应用my_company
有两个模型Employee
和Dependent
。 my_company
中的员工可以拥有的不仅仅是家属(换句话说,受抚养人可以是单个员工的儿子/女儿,而员工可以有多个子女/女儿)。
呃,假设丈夫和妻子都不能在my_company
工作。我拿了1:m的例子
因此,Employee
是引用模型,可以由引用模型的Dependent
引用。现在考虑如下关系状态:
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
引用。
现在我的查询是:
找到所有有儿子/女儿的员工在大学和学校都有区别标记(比如> = 75%)?
>>> Employee.objects.filter(dependent__school_mark__gte=75,
... dependent__college_mark__gte=75)
[<Employee: A>]
输出是'A'依赖'a1'在大学和学校都有区别标记依赖于员工'A'。注意'B'未被选中,因为'B'的孩子在大学和学校都有区别标记。关系代数:
员工⋈ (school_mark&gt; = 75 AND college_mark&gt; = 75)依赖
在第二种情况下,我需要一个查询:
查找所有在大学和学校中有一些家属有区别标记的员工?
>>> 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&gt; = 75)依赖)⋈ (college_mark&gt; = 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.query
和print qd2.query
检查Django生成的目标SQL查询是否相同(Django 1.6)。
但语义上两者都与 me 不同。首先看起来像简单的部分σ [school_mark&gt; = 75 AND college_mark&gt; = 75] (依赖),第二个看起来像慢嵌套查询:σ [school_mark&gt; = 75] (σ [college_mark&gt; = 75] (Dependent))。
如果需要Code @codepad
顺便说一句,它是在文档@ Spanning multi-valued relationships中给出的。我刚刚添加了一个示例,我认为这对新的人有用。
答案 3 :(得分:8)
性能差异很大。试试吧,看看。
Model.objects.filter(condition_a).filter(condition_b).filter(condition_c)
出乎意料地缓慢
Model.objects.filter(condition_a, condition_b, condition_c)
- QuerySets维护内存中的状态
- 链接触发克隆,复制该状态
- 不幸的是,QuerySets维护了很多状态
- 如果可能,请不要链接多个过滤器
答案 4 :(得分:6)
您可以使用连接模块查看要比较的原始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)
>>>
答案 5 :(得分:3)
此答案基于Django 3.1。
环境
模型
class Blog(models.Model):
blog_id = models.CharField()
class Post(models.Model):
blog_id = models.ForeignKeyField(Blog)
title = models.CharField()
pub_year = models.CharField() # Don't use CharField for date in production =]
数据库表
过滤通话
Blog.objects.filter(post__title="Title A", post__pub_year="2020")
# Result: <QuerySet [<Blog: 1>]>
Blog.objects.filter(post__title="Title A").filter(post_pub_date="2020)
# Result: <QuerySet [<Blog: 1>, [<Blog: 2>]>
说明
在开始任何事情之前,我必须注意到,这个答案是基于使用“ ManyToManyField”或反向“ ForeignKey”来过滤对象的情况的。
如果您使用相同的表或“ OneToOneField”来过滤对象,则使用“多个参数过滤器”或“过滤器链”之间没有区别。它们都将像“ AND”条件过滤器一样工作。
了解如何使用“多个参数过滤器”和“过滤器链”的直接方法是记住“ ManyToManyField”或反向“ ForeignKey”过滤器,“多个参数过滤器”为“ AND”条件而“过滤链”是“或”条件。
使“多参数过滤器”和“过滤器链”如此不同的原因是,它们从不同的联接表中获取结果并在查询语句中使用不同的条件。
“多个参数过滤器”使用“发布”。“ Public_Year” ='2020'标识公共年份
SELECT *
FROM "Book"
INNER JOIN ("Post" ON "Book"."id" = "Post"."book_id")
WHERE "Post"."Title" = 'Title A'
AND "Post"."Public_Year" = '2020'
“过滤链”数据库查询使用“ T1”。“ Public_Year” ='2020'标识公共年份
SELECT *
FROM "Book"
INNER JOIN "Post" ON ("Book"."id" = "Post"."book_id")
INNER JOIN "Post" T1 ON ("Book"."id" = "T1"."book_id")
WHERE "Post"."Title" = 'Title A'
AND "T1"."Public_Year" = '2020'
但是为什么不同的条件会影响结果?
我相信来到此页面的我们大多数人,包括我=],在最初使用“多重参数过滤器”和“过滤器链”时都具有相同的假设。
我们认为应该从一张类似于“多参数过滤器”正确的表中获取结果。因此,如果您使用“多个参数过滤器”,则会得到预期的结果。
但是在处理“过滤器链”时,Django创建了另一个查询语句,该语句将上表更改为下一个表。另外,由于查询语句的更改,在“ T1”部分下而不是“ Post”部分下标识了“ Public Year”。
但是这个奇怪的“过滤链”联接表图是从哪里来的?
我不是数据库专家。在创建了相同的数据库结构并使用相同的查询语句进行了测试之后,到目前为止,下面的解释是我所了解的。
下图将显示此奇怪的“过滤链”联接表图的来源。
数据库将首先通过将“博客”和“发布”表的行一一匹配来创建联接表。
此后,数据库现在再次执行相同的匹配过程,但使用步骤1结果表来匹配与同一“ Post”表相同的“ T1”表。
这就是这个奇怪的“过滤链”联接表图的来源。
结论
所以有两件事使“多重参数过滤器”和“过滤器链”变得不同。
记住使用方法的肮脏方式是“多个参数过滤器”是“ AND” 条件,而“过滤器链”是“ OR” 条件而在“ ManyToManyField”或反向“ ForeignKey”过滤器中。
答案 6 :(得分:1)
如果您最终在此页面上查找如何使用多个链接过滤器动态构建django查询集,但您需要将过滤器设置为AND
类型而不是OR
,请考虑使用Q objects
一个例子:
# 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)
答案 7 :(得分:0)
如果需要a和b,则
and_query_set = Model.objects.filter(a=a, b=b)
如果需要a和b则
chaied_query_set = Model.objects.filter(a=a).filter(b=b)
正式文件: https://docs.djangoproject.com/en/dev/topics/db/queries/#spanning-multi-valued-relationships
答案 8 :(得分:-2)
从django.db.models导入Q
&是=布尔值(i) |是=布尔(o)
models.objects.filter(Q(id = self.kwargs ['pk'])&Q(date = self.kwargs ['date'])) models.objects.filter(Q(id = self.kwargs ['pk'])| Q(date = self.kwargs ['date']))
答案 9 :(得分:-3)
当您对相关对象提出请求时,存在差异, 例如
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