2

私はこの行動に完全に困惑しています。私は自分が思っていたように 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 をクエリに追加するのは不必要に思えますが、非常に必要です。

4

2 に答える 2

3

2 つのオブジェクトを取得していて、それが同じである場合は、そのオブジェクトが少なくとも 2 つのクエリセットを満たしているためです。

つまり、<SchedulerEvent: andrew>少なくとも 2 つのクエリセットで満たす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 つの要素に一致するため、実際に一致するのは 1 つだけであることを受け入れてください。Q オブジェクトは、データベースでクエリを検索するなど、正しく使用すると非常に強力です。この例では、Q オブジェクトは必要ありませんが、単純なフィルターで問題なく機能します。

.filter(...)あなたの場合、シンプルな動作を試しましたか?

結局、Q オブジェクトがそのクエリセットを返す理由を理解しようとしていません。あなたは特定の結果を得ようとしており、正常にdistinct()動作します:)

于 2015-04-17T08:48:15.767 に答える