Django Q 对象和 m2m 查询

Django Q objects and m2m queries

我对这种行为感到非常困惑。我显然不像我想的那样理解 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>]

关于 returns 两个对象的这个 OR 查询是什么意思,我相信很清楚,应该只有一个?

编辑

所以我查看了生成的查询,似乎 "answer" 与 Q 对象或 OR'ing 完全无关;相反,这是 ORM 加入 table 的方式。这是 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 似乎 没有必要,但这是非常必要的。

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

换句话说,<SchedulerEvent: andrew>满足至少两个查询集r l o

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

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

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

您是否尝试过简单的 .filter(...) 在您的案例中的表现?

最后你不是想理解为什么Q对象会return那个queryset;您正在尝试获得某个结果,并且 distinct() 工作正常:)