2

我完全被这种行为弄糊涂了。我显然不像我想的那样理解 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似乎没有必要,但这是非常必要的。

4

2 回答 2

3

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

换句话说,<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()
于 2015-04-17T01:55:40.383 回答
1

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

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

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

于 2015-04-17T08:48:15.767 回答