django - 来自 AND 操作和顺序过滤器的 Django diffrenet 结果
问题描述
如果我有这样的模型:
class Person(models.Model):
first_name = models.CharField(max_length=20)
last_name = models.CharField(max_length=20)
class PersonSession(models.Model):
start_time = models.DateTimeField(auto_now_add=True)
end_time = models.DateTimeField(null=True,
blank=True)
person = models.ForeignKey(Person, related_name='sessions')
class Billing(models.Model):
DEBT = 'DE'
BALANCED = 'BA'
CREDIT = 'CR'
session = models.OneToOneField(PersonSession,
blank=False,
null=False,
related_name='billing')
STATUS = ((BALANCED, 'Balanced'),
(DEBT, 'Debt'),
(CREDIT, 'Credit'))
status = models.CharField(max_length=2,
choices=STATUS,
blank=False,
default=BALANCED
)
下面的两个查询会产生不同的结果:
Person.objects.filter(Q(sessions__start_time__gte='2000-02-01') & \
Q(sessions__start_time__lte='2000-03-01') & \
Q(sessions__billing__status=Billing.DEBT))
OR
Person.objects.filter(Q(sessions__start_time__gte='2000-02-01') & \
Q(sessions__start_time__lte='2000-03-01')).filter(
Q(sessions__billing__status=Billing.DEBT))
第一个生成两个人 1,2,第二个生成我拥有的所有三个人,数据如下:
id | first_name | last_name | id | start_time | end_time | person_id | id | status | session_id
---+------------+-----------+----+---------------------------+---------------------------+-----------+----+--------+------------
0 | person | 0 | 0 | 2000-01-01 16:32:00+03:30 | 2000-01-01 17:32:00+03:30 | 0 | 0 | DE | 0
0 | person | 0 | 1 | 2000-02-01 16:32:00+03:30 | 2000-02-01 17:32:00+03:30 | 0 | 1 | BA | 1
0 | person | 0 | 2 | 2000-03-01 16:32:00+03:30 | 2000-03-01 17:32:00+03:30 | 0 | 2 | DE | 2
1 | person | 1 | 3 | 2000-01-01 16:32:00+03:30 | 2000-01-01 17:32:00+03:30 | 1 | 3 | BA | 3
1 | person | 1 | 4 | 2000-02-01 16:32:00+03:30 | 2000-02-01 17:32:00+03:30 | 1 | 4 | DE | 4
1 | person | 1 | 5 | 2000-03-01 16:32:00+03:30 | 2000-03-01 17:32:00+03:30 | 1 | 5 | DE | 5
2 | person | 2 | 6 | 2000-01-01 16:32:00+03:30 | 2000-01-01 17:32:00+03:30 | 2 | 6 | DE | 6
2 | person | 2 | 7 | 2000-02-01 16:32:00+03:30 | 2000-02-01 17:32:00+03:30 | 2 | 7 | DE | 7
2 | person | 2 | 8 | 2000-03-01 16:32:00+03:30 | 2000-03-01 17:32:00+03:30 | 2 | 8 | BA | 8
我写了一个示例,为它们创建类和数据以显示差异。
请解释这两个查询之间有什么区别,如果在 django-filter 包中我想定义一些字段作为第一个过滤器,我该怎么做?
解决方案
过滤器生成的查询不同,如下所示:
>>> print Person.objects.filter(Q(sessions__start_time__gte='2000-02-01') & \
... Q(sessions__start_time__lte='2000-03-01')).filter(
... Q(sessions__billing__status=Billing.DEBT)).query
SELECT "test_filter_person"."id", "test_filter_person"."first_name", "test_filter_person"."last_name" FROM "test_filter_person" INNER JOIN "test_filter_personsession" ON ("test_filter_person"."id" = "test_filter_personsession"."person_id") INNER JOIN "test_filter_personsession" T3 ON ("test_filter_person"."id" = T3."person_id") INNER JOIN "test_filter_billing" ON (T3."id" = "test_filter_billing"."session_id") WHERE ("test_filter_personsession"."start_time" >= 2000-02-01 00:00:00+00:00 AND "test_filter_personsession"."start_time" <= 2000-03-01 00:00:00+00:00 AND "test_filter_billing"."status" = DE)
>>> print Person.objects.filter(Q(sessions__start_time__gte='2000-02-01') & \
... Q(sessions__start_time__lte='2000-03-01') & \
... Q(sessions__billing__status=Billing.DEBT)).query
SELECT "test_filter_person"."id", "test_filter_person"."first_name", "test_filter_person"."last_name" FROM "test_filter_person" INNER JOIN "test_filter_personsession" ON ("test_filter_person"."id" = "test_filter_personsession"."person_id") INNER JOIN "test_filter_billing" ON ("test_filter_personsession"."id" = "test_filter_billing"."session_id") WHERE ("test_filter_personsession"."start_time" >= 2000-02-01 00:00:00+00:00 AND "test_filter_personsession"."start_time" <= 2000-03-01 00:00:00+00:00 AND "test_filter_billing"."status" = DE)
我们分别称它们为 Q1 和 Q2。
如您所见,Q1 在 、 和 之间进行了一次连接Person
,PersonSession
并且Billing
所有条件都在WHERE
子句中一起应用。
但是,在 Q2 中,由于您使用前两个检查终止了第一个过滤器,因此这会导致和之间的第一个查询连接Person
(PersonSession
对于Person.objects.filter(Q(sessions__start_time__gte='2000-02-01') & Q(sessions__start_time__lte='2000-03-01'))
,结果这个第一个连接再次与PersonSession
和连接Billing
,以便执行过滤器的第二部分查询.filter(Q(sessions__billing__status=Billing.DEBT))
。
您可以在此处阅读更多内容:django 中具有多个参数的过滤器和链式过滤器之间的区别
还想提请您注意帖子的最后一行:
一张表:但是如果查询不涉及连接表,例如 Yuji 和 DTing 中的示例。结果是一样的。
推荐阅读
- javascript - 如何在 React 应用程序中覆盖或取消容器的 CSS 填充
- c - c链表追加插入
- html - css 如何使链接的背景表现得像链接本身?
- javascript - 具有均匀面的程序圆网格
- c# - 导出带有图像和文件的 WindowsForm
- python - 硒 python 网页抓取
- java - 上滑面板 android 构建失败
- tensorflow - keras层输入大小中问号(?)的含义
- java - 如何在没有并发修改异常的情况下进行连续循环收集
- flutter - 错误:[dart] 参数类型“Context”不能分配给参数类型“BuildContext”。[argument_type_not_assignable]