Очень странное поведение, касающееся фильтрации ManyToMany и объединения наборов запросов - PullRequest
1 голос
/ 18 апреля 2019

Календари имеют владельца и имеют поле ManyToMany «Помощники». У меня есть Календарь, у которого есть 2 помощника, один из которых является его владельцем.Я думаю, что эти 3 строки кода в оболочке django могут достаточно хорошо объяснить странное поведение.

In [17]: Calendar.objects.filter(assistants=customer).exclude(owner=customer)                             
Out[17]: <QuerySet []>
In [20]: Calendar.objects.filter(owner=customer)                                                          
Out[20]: <QuerySet [<Calendar: aliz cal>, <Calendar: yassi has a calendar>]>
In [19]: Calendar.objects.filter(owner=customer) | Calendar.objects.filter(assistants=customer).exclude(owner=customer)                                                                                    
Out[19]: <QuerySet [<Calendar: aliz cal>, <Calendar: aliz cal>, <Calendar: yassi has a calendar>]>

Конечно, ожидалось, что результатом объединения запросов будет их фактическое объединение.

Ответы [ 2 ]

1 голос
/ 18 апреля 2019

Предполагается, что это для django 1.11 +:
| не представляет объединение.Он представляет собой комбинацию OR (которая поддерживает все объединения; следовательно, aliz отображается дважды) из двух наборов запросов.

qs1.filter(x=1) | qs2.exclude(x=1) переводится в:

SELECT STUFF FROM TABLES_AND_JOINS WHERE (x = 1 OR NOT (x = 1))

Хотяqs1.filter(x=1).union(qs2.exclude(x=1)) переводится в:

SELECT STUFF FROM TABLE1 WHERE x = 1 UNION SELECT STUFF FROM TABLE2 WHERE NOT x = 1

Используйте str(qs.query) для просмотра SQL.

0 голосов
/ 18 апреля 2019

То, что вы делаете, - это OR, то есть предложения WHERE обоих запросов, что отличается от объединения (и немного сложнее при объединении; здесь ORM переключается из внутреннего соединения в набор запросов # 1 к внешнему соединению в наборе запросов № 3, чтобы учесть второй запрос, который не имеет соединений). См. Соответствующие документы .

Попробуйте union(), доступно с Django 1.11 и далее:

qs1 = Calendar.objects.filter(assistants=customer).exclude(owner=customer)                             
qs2 = Calendar.objects.filter(owner=customer) 
qs3 = qs1.union(qs2)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...