私はこの行動に完全に困惑しています。私は自分が思っていたように Q オブジェクトを明らかに理解していないか、非常に愚かで明白なことをしています。これが私が遭遇しているものです。Accepted_attendee_* はすべて、OfficialProfile との m2m 関係です。デモンストレーションを簡単にするために、django シェルで。
>>> 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 を持つ 2 つのオブジェクトが返されます。つまり、2 つの重複オブジェクトです。個々のクエリに基づいて、1 つだけにする必要があります。しかし、もう一度、これを行うと:
>>> r|l|o
[<SchedulerEvent: andrew>, <SchedulerEvent: andrew>]
この OR クエリでは、オブジェクトが 1 つだけであるべきなのに、2 つのオブジェクトが返されるのはなぜでしょうか?
編集
そこで、生成されたクエリを調べたところ、「答え」は Q オブジェクトや OR とはまったく関係がないようです。むしろ、ORM がテーブルを結合する方法です。OR がない場合の SQL とそれが生成する結果は次のとおりです。
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 を追加すると、結合の結果に基づいて 2 つのクエリ条件が満たされます。したがって、distinct をクエリに追加するのは不必要に思えますが、非常に必要です。