【问题标题】:Django Q objects and m2m queriesDjango Q 对象和 m2m 查询
【发布时间】:2015-06-23 16:39:44
【问题描述】:

我完全被这种行为弄糊涂了。我显然不像我想的那样理解 Q 对象,或者我正在做一些非常愚蠢和明显的事情。这就是我遇到的问题。 accepted_attendee_* 都是与 OfficialProfile 的 m2m 关系。在 django shell 中,为了便于演示。

>>> profile = OfficialProfile.objects.get(user__username='testofficial3')
>>> r = SchedulerEvent.objects.filter(accepted_attendee_referee=profile)
>>> l = SchedulerEvent.objects.filter(accepted_attendee_linesman=profile)
>>> o = SchedulerEvent.objects.filter(accepted_attendee_official=profile)
>>> r
[<SchedulerEvent: andrew>]
>>> l
[]
>>> o
[]

这一切都符合预期。现在,如果我与 Q 对象结合在一起,事情会变得很奇怪。

>>> qevents = SchedulerEvent.objects.filter(Q(accepted_attendee_referee=profile)|Q(accepted_attendee_official=profile)|Q(accepted_attendee_linesman=profile))
>>> qevents
[<SchedulerEvent: andrew>, <SchedulerEvent: andrew>]

返回两个对象,它们都具有相同的 PK - 两个重复的对象。根据个人查询,应该只有一个。但再一次,当我这样做时:

>>> r|l|o
[<SchedulerEvent: andrew>, <SchedulerEvent: andrew>]

这个 OR 查询返回两个对象的原因是什么,我相信很清楚,应该只有一个?

编辑

所以我查看了生成的查询,似乎“答案”与 Q 对象或 OR'ing 无关;相反,这是 ORM 加入表的方式。这是 SQL 及其生成的结果,没有 OR:

mysql> SELECT `scheduler_schedulerevent`.`id`, `scheduler_schedulerevent`.`user_id`, `scheduler_schedulerevent`.`title`, `scheduler_schedulerevent`.`description`, `scheduler_schedulerevent`.`start`, `scheduler_schedulerevent`.`end`, `scheduler_schedulerevent`.`location_id`, `scheduler_schedulerevent`.`age_level_id`, `scheduler_schedulerevent`.`skill_level_id`, `scheduler_schedulerevent`.`officiating_system_id`, `scheduler_schedulerevent`.`auto_schedule`, `scheduler_schedulerevent`.`is_scheduled` 
FROM `scheduler_schedulerevent` 
LEFT OUTER JOIN `scheduler_schedulerevent_accepted_attendee_referee` 
ON ( `scheduler_schedulerevent`.`id` = `scheduler_schedulerevent_accepted_attendee_referee`.`schedulerevent_id` ) 
LEFT OUTER JOIN `scheduler_schedulerevent_accepted_attendee_linesman` 
ON ( `scheduler_schedulerevent`.`id` = `scheduler_schedulerevent_accepted_attendee_linesman`.`schedulerevent_id` ) 
LEFT OUTER JOIN `scheduler_schedulerevent_accepted_attendee_official` 
ON ( `scheduler_schedulerevent`.`id` = `scheduler_schedulerevent_accepted_attendee_official`.`schedulerevent_id` );

+----+---------+---------------+-------------+---------------------+---------------------+-------------+--------------+----------------+-----------------------+---------------+--------------+
| id | user_id | title         | description | start               | end                 | location_id | age_level_id | skill_level_id | officiating_system_id | auto_schedule | is_scheduled |
+----+---------+---------------+-------------+---------------------+---------------------+-------------+--------------+----------------+-----------------------+---------------+--------------+
|  1 |       1 | Test Event    |             | 2015-04-09 02:00:00 | 2015-04-09 02:30:00 |         161 |            1 |              1 |                     3 |             0 |            0 |
|  2 |       1 | Test          |             | 2015-04-07 20:00:00 | 2015-04-07 21:00:00 |         161 |            1 |              1 |                     3 |             1 |            0 |
|  3 |       1 | Test Auto     |             | 2015-04-07 20:00:00 | 2015-04-07 20:30:00 |         161 |            1 |              1 |                     2 |             0 |            0 |
|  4 |       1 | Test Official |             | 2015-04-16 19:00:00 | 2015-04-16 20:30:00 |         161 |            1 |              1 |                     3 |             0 |            1 |
|  4 |       1 | Test Official |             | 2015-04-16 19:00:00 | 2015-04-16 20:30:00 |         161 |            1 |              1 |                     3 |             0 |            1 |
+----+---------+---------------+-------------+---------------------+---------------------+-------------+--------------+----------------+-----------------------+---------------+--------------+

然后很明显,当你添加一个 OR 时,它根据连接的结果满足两个查询条件。因此,虽然在查询中添加 distinct 似乎 是不必要的,但这是非常必要的。

【问题讨论】:

    标签: python django django-models django-q


    【解决方案1】:

    如果你得到两个对象并且它是相同的,那是因为那个对象至少满足两个查询集。

    换句话说,&lt;SchedulerEvent: andrew&gt; 至少满足两个查询集r l o

    如果您不想重复对象,请使用.distinct() 函数。

    SchedulerEvent.objects.filter(Q(accepted_attendee_referee=profile)|Q(accepted_attendee_official=profile)
    |Q(accepted_attendee_linesman=profile)).distinct()
    

    【讨论】:

    • 我意识到我可以使用 distinct,但这并不能回答关于对象如何以及为什么满足两个 quesysets 的问题。它基本上是相同的查询,结合 or 子句。如果 >>> r.count()+l.count()+o.count() 等于 1 怎么会 >>> qevents.count() 等于 2?说真的,我是不是很厚?
    【解决方案2】:

    不,你不是很厚,但只需接受底层系统(django 的 ORM)和 Q 对象将匹配 2 个相同的元素,因此实际上只有一个匹配。 Q 对象在正确使用时非常强大,例如在数据库中搜索查询。在此示例中,您不需要 Q 对象,但简单的过滤器可以正常工作。

    您是否尝试过简单的.filter(...) 在您的情况下的行为?

    最后,您并没有试图理解为什么 Q 对象会返回该查询集;您正在尝试获得某个结果,distinct() 工作正常 :)

    【讨论】:

      猜你喜欢
      • 2010-12-27
      • 2014-02-06
      • 2015-07-15
      • 2021-09-15
      • 1970-01-01
      • 2017-09-16
      • 2013-12-11
      • 2010-11-13
      相关资源
      最近更新 更多