2015-04-17 61 views
2

我完全被这种行为所迷惑。我清楚地不理解我认为我所做过的Q对象,或者我正在做一些非常愚蠢和明显的事情。这是我遇到的问题。 accepted_attendee_ *与OfficialProfile都是m2m关系。在django shell中,为了便于演示。Django Q对象和m2m查询

>>> 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>] 

这是关于这个或查询返回两个对象时应该有,我相信很清楚,只有一个?

编辑

所以,我看着那个被产生的查询,它似乎像“答案”没有任何关系符合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,它的基础上的连接的结果符合两项查询条件。所以虽然增加不同的查询似乎不必要的,这是非常必要的。

回答

3

如果您获取两个对象并且它是相同的,那是因为该对象满足至少两个queryset。

换句话说,<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() 
+1

我知道我可以用不同的,但是,这并不回答关于如何以及为什么对象符合两项quesysets的问题。它基本上是相同的查询,结合或子句。如果>>> r.count()+ l.count()+ o.count()等于1,heck可以如何>>> qevents.count()等于2?说真的,我是不是很厚? – ghiotion

1

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

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

最后你并没有试图去理解为什么Q对象会返回那个查询集;你试图得到某种结果,而distinct()工作得很好:)