27

I have to querysets. alllists and subscriptionlists

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

I need a queryset called unsubscriptionlist, which possess all records in alllists except the records in subscription lists. How to achieve this?

halfer
  • 19,471
  • 17
  • 87
  • 173
Rajasekar
  • 17,868
  • 32
  • 99
  • 135
  • The two querysets in your example appear to use different models. They would need to be using the same model for your question to make sense. – Aram Dulyan May 10 '11 at 08:04
  • 1
    This is a related answer which is much more concise- http://stackoverflow.com/questions/8867743/how-does-one-find-the-entities-in-a-django-query-set-that-are-not-in-another-spe – Devang Nov 02 '13 at 08:07

4 Answers4

28

Since Django 1.11, QuerySets have a difference() method amongst other new methods:

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

Also see: https://stackoverflow.com/a/45651267/5497962

funnydman
  • 4,408
  • 3
  • 22
  • 42
markus-hinsche
  • 1,242
  • 15
  • 26
17

You should be able to use the set operation difference to help:

set(alllists).difference(set(subscriptionlists))
Brian Fisher
  • 22,731
  • 15
  • 76
  • 81
11

Well I see two options here.

1. Filter things manually (quite ugly)

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. Just make another query

diff = List.objects.filter(datamode = 'A').exclude(member__id=memberid, datamode='A')
Silver Light
  • 41,576
  • 32
  • 119
  • 161
4

How about:

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

The unsubscriptionlists should be the inverse of subscription lists.

Brian's answer will work as well, though set() will most likely evaluate the query and will take a performance hit in evaluating both sets into memory. This method will keep the lazy initialization until you need the data.

Gevious
  • 3,103
  • 2
  • 19
  • 41
  • `unsubscriptionlists = Membership.objects.exclude(member__id=memberid, datamode='A')` should be: `unsubscriptionlists = Membership.objects.filter(datamode='A').exclude(member__id=memberid)` – Chris Pratt May 10 '11 at 21:28