Як я можу знайти об'єднання двох наборів запитів Django?


93

У мене є модель Django з двома методами спеціального менеджера. Кожен повертає різну підмножину об’єктів моделі на основі іншої властивості об’єкта.

Чи є спосіб отримати набір запитів або просто список об’єктів, що є об’єднанням наборів запитів, що повертаються кожним методом менеджера?


3
(З видаляється відповіді) Дивіться це питання для зміни , яке працює з QuerySets різних моделей: stackoverflow.com/questions/431628 / ...
rnevius

1
Починаючи з версії 1.11, набори запитів django мають вбудований метод об'єднання. Я додав його як відповідь для подальшої довідки
Хосе Черіан

Відповіді:


179

Це працює і виглядає дещо чистішим:

records = query1 | query2

Якщо ви не хочете дублікатів, вам потрібно буде додати .distinct():

records = (query1 | query2).distinct()

5
Хоча прийнята відповідь повертає об'єднання, яке можна повторити (точніше, список), як це запитував OP, цей метод повертає справжнє об'єднання наборів запитів. Цей набір запитів можна оперувати надалі, що бажано за багатьох обставин.
Krystian Cybulski

5
Через помилку Django ця конструкція іноді може повертати неправильні результати при роботі з ManyToManyFields. Наприклад, іноді ви побачите, що records.count()це буде більше ніж query1.count() + query2.count(), що явно неправильно.
Jian

4
@Jian, ти можеш пояснити версію django із помилкою та посиланням на проблему djangoproject?
IMFletcher

10
записи = запит1 | запит2; records = records.distinct () дасть мені правильний результат
Євген

5
Ви можете перевантажити оператори в Python. Див. Docs.python.org/2/library/operator.html . Отже, що робить Django - це створення спеціальних методів для об’єкта QuerySet. Дивіться код тут: github.com/django/django/blob/master/django/db/models / ...QuerySet клас надає методи __and__і __or__які викликаються , коли &або |використовуються оператори між двома QuerySetоб'єктами (також використовуються для Qкласу , а також ).
Йорданія Рейтер

49

Починаючи з версії 1.11 , набори запитів django мають вбудований метод об'єднання.

q = q1.union(q2) #q will contain all unique records of q1 + q2
q = q1.union(q2, all=True) #q will contain all records of q1 + q2 including duplicates
q = q1.union(q2,q3) # more than 2 queryset union

Докладніші приклади див. У моєму блозі .


Я не зміг отримати все = Правда працювати. Закінчився приведенням мого набору запитів до набору, перш ніж повернути його клієнту.
Брейден Холт

1
@BradenHolt, all = True, означає, що він буде містити повторювані записи. Ви можете просто видалити all = True, щоб уникнути передачі його набору.
Хосе

після цього не працює DjangoFilterBackend, як я можу використовувати union та DjangoFilterBackend?
nesalexy

На жаль, це не працює для моделей із упорядкуванням за замовчуванням, визначеним у Мета моделі. Кожного разу, коли я намагаюся поєднати їх із .union, я отримую таку помилку: "ORDER BY не дозволяється в підзапитах складених операторів."
суд

4

Я б запропонував використовувати 'query1.union (query2)' замість 'query1 | запит2 '; Я отримав різні результати від вищезазначених двох методів, і перший я очікував. Я натрапив на таке:

print "union result:"
for element in query_set1.union(query_set2):
    print element

print "| result:"
for element in (query_set1 | query_set2):
    print element

результат:

union result:
KafkaTopic object
KafkaTopic object
KafkaTopic object
KafkaTopic object
KafkaTopic object

| result:
KafkaTopic object
KafkaTopic object

1
Вставте код, а не зображення коду. Текст на зображеннях недоступний для пошуку, ви не можете скопіювати / вставити його у свій редактор для перевірки та займає більше місця, ніж потрібно. Використовуйте зворотні позначки, щоб позначити код як код, щоб він був правильно відформатований. Дивіться посилання "довідка" поруч із полем введення тексту.
суд

Дякуємо за оновлення. :)
суд,
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.