Как получить разницу между двумя наборами запросов в Django?

Мне нужно выполнить запросы. все списки и подписные списки

alllists = List.objects.filter(datamode = 'A')
subscriptionlists = Membership.objects.filter(member__id=memberid, datamode='A')

Мне нужен набор запросов с именем unsubscriptionlist, который содержит все записи во всех списках, кроме записей в списках подписки. Как этого добиться?


person Rajasekar    schedule 10.05.2011    source источник
comment
Два набора запросов в вашем примере, по-видимому, используют разные модели. Им нужно будет использовать ту же модель, чтобы ваш вопрос имел смысл.   -  person Aram Dulyan    schedule 10.05.2011
comment
Это связанный ответ, который гораздо более лаконичен: that-are-not-in-another-spe" title="как найти объекты в наборе запросов django, которых нет в другом spe"> stackoverflow.com/questions/8867743/   -  person Devang    schedule 02.11.2013


Ответы (4)


Начиная с Django 1.11, QuerySets имеет метод difference() среди других новых методов:

# Capture elements that are in qs_all but not in qs_part
qs_diff = qs_all.difference(qs_part)    

Также см.: https://stackoverflow.com/a/45651267/5497962

person markushinsche    schedule 05.10.2017
comment
Как я могу это сделать в Django 1.10? - person Artem Dumanov; 24.03.2018

Вы должны иметь возможность использовать разницу операций набора, чтобы помочь:

set(alllists).difference(set(subscriptionlists))
person Brian Fisher    schedule 10.05.2011
comment
Слишком сложное решение, когда вы можете просто использовать exclude вместо filter - person Chris Pratt; 11.05.2011
comment
Да, это определенно не оптимально, если желаемый результат может быть получен с помощью одного набора запросов, но если по какой-то причине это невозможно, это жизнеспособное решение. - person Brian Fisher; 11.05.2011
comment
Истинный. Не учел этого. Хорошая информация, которую можно оставить для тех, кто занимается сложной математикой запросов. - person Chris Pratt; 11.05.2011
comment
И еще один способ сделать то же самое: set(alllists) - set(ssubscriptionlists) - person lurknobserve; 23.01.2017

Ну тут я вижу два варианта.

1. Фильтруйте вещи вручную (довольно некрасиво)

diff = []
for all in alllists:
    found = False
    for sub in subscriptionlists:
        if sub.id == all.id:
            found = True 
            break
    if not found:
        diff.append(all)

2. Просто сделайте еще один запрос

diff = List.objects.filter(datamode = 'A').exclude(member__id=memberid, datamode='A')
person Silver Light    schedule 10.05.2011

Как насчет:

subscriptionlists = Membership.objects.filter(member__id=memberid, datamode='A')
unsubscriptionlists = Membership.objects.exclude(member__id=memberid, datamode='A')

Списки отказа от подписки должны быть обратными спискам подписки.

Ответ Брайана также будет работать, хотя set(), скорее всего, оценит запрос и снизит производительность при оценке обоих наборов в памяти. Этот метод сохранит ленивую инициализацию до тех пор, пока вам не понадобятся данные.

person Gevious    schedule 10.05.2011
comment
unsubscriptionlists = Membership.objects.exclude(member__id=memberid, datamode='A') должно быть: unsubscriptionlists = Membership.objects.filter(datamode='A').exclude(member__id=memberid) - person Chris Pratt; 11.05.2011