简体   繁体   English

Django Q对象和M2M查询

[英]Django Q objects and m2m queries

I'm totally flummoxed by this behavior. 我完全被这种行为弄糊涂了。 I clearly don't understand Q objects like I thought I did or I'm doing something massively stupid and obvious. 我显然不了解Q对象,就像我以为自己做的那样,或者我正在做一些愚蠢而明显的事情。 Here's what I'm running into. 这就是我遇到的问题。 accepted_attendee_* are all m2m relationships to OfficialProfile. accept_attendee_ *是与OfficialProfile的所有m2m关系。 In the django shell, for ease of demonstration. 在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
[]

This is all as expected. 这完全符合预期。 Now tho, if I combine together with a Q object, things get weird. 现在,如果我与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>]

Two objects are returned, both with the same PK - two duplicate objects. 返回两个具有相同PK的对象-两个重复的对象。 Should be only one, based on the individual queries. 根据各个查询,只能是一个。 But once again, when I do this: 但是再次,当我这样做时:

>>> r|l|o
[<SchedulerEvent: andrew>, <SchedulerEvent: andrew>]

What is it about this OR query that returns two objects when there should, I believe quite clearly, be only one? 我很清楚地知道,当仅应存在一个对象时,返回两个对象的OR查询有什么用?

EDIT 编辑

So I looked at the query that was produced and it seems like the "answer" has nothing to do with Q objects or the OR'ing at all; 因此,我查看了所产生的查询,似乎“答案”与Q对象或“或”操作无关。 rather, it's the way the ORM joins the table. 而是ORM连接表的方式。 Here's the SQL and the results it generates, absent the OR: 这是缺少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 |
+----+---------+---------------+-------------+---------------------+---------------------+-------------+--------------+----------------+-----------------------+---------------+--------------+

and then clearly, when you add an OR, it satisfies two query conditions based on the results of the join. 然后很明显,当您添加OR时,它会根据联接的结果满足两个查询条件。 So while adding distinct to the query seems unnecessary, it is quite necessary. 因此,虽然在查询中添加唯一性似乎是不必要的,但这是非常必要的。

If you are getting two objects and it is the same, is because that object satisfies at least two queryset. 如果要获得两个对象并且它是相同的,那是因为该对象至少满足两个查询集。

In other words, <SchedulerEvent: andrew> satisfy with at least two queryset rlo 换句话说, <SchedulerEvent: andrew>至少满足两个rlo

If you don't want duplicate objects, use .distinct() function. 如果不想重复对象,请使用.distinct()函数。

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

No you aren't being thick , but just accept that the underlying system (django's ORM) and Q objects will match 2 elements which are the same and therefore only one is actually matched. 不,您不是不是很胖,只是接受基础系统(django的ORM)和Q对象将匹配2个相同的元素,因此实际上只有一个匹配。 Q objects are very powerful when used correctly such as searching a query in a database. 如果正确使用Q对象(例如在数据库中搜索查询),则Q对象非常强大。 In this example you do not need Q objects but a simple filter would work fine. 在此示例中,您不需要Q对象,但是简单的过滤器可以正常工作。

Have you tried how a simple .filter(...) behaves in your case? 您是否尝试过简单的.filter(...)在您的情况下的行为?

In the end you are not trying to understand why it is so that Q objects will return that queryset; 最后,您不会试图理解为什么会这样,以便Q对象返回该查询集。 you are trying to get a certain result, and distinct() works fine :) 您正在尝试获得一定的结果,并且distinct()可以正常工作:)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM