Django diffrenet来自AND操作和顺序过滤器

时间:2018-05-09 10:12:31

标签: django django-models django-queryset django-filters

如果我有这样的模型:

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

我写了一个example,为他们创建类和数据以显示差异。

请解释这两个查询之间有什么区别,作为一个附带问题,如果在django-filter包中我想定义一些字段作为第一个过滤器,我怎么能这样做?

1 个答案:

答案 0 :(得分:1)

过滤器生成的查询不同,如下所示:

>>> 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会在PersonPersonSessionBilling之间进行一次联接,并且所有条件都会在WHERE子句中一起应用。< / p>

但是,在Q2中,由于您使用前两个检查终止了第一个过滤器,因此首先在PersonPersonSession之间进行第一次查询连接(对于Person.objects.filter(Q(sessions__start_time__gte='2000-02-01') & Q(sessions__start_time__lte='2000-03-01')),结果第一次加入再次与PersonSessionBilling合并,以便执行过滤查询.filter(Q(sessions__billing__status=Billing.DEBT))的第二部分。

您可以在此处阅读更多内容:difference between filter with multiple arguments and chain filter in django

还想提请你注意帖子的最后一行:

  

一个表格:但是如果查询不涉及连接表,例如Yuji和DTing的示例。结果是一样的。