Reputation: 18978
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?
Upvotes: 29
Views: 32812
Reputation: 2139
In case anyone's searching for a way to do symmetric difference, such operator is not available in Django.
That said, it's not that hard to implement it using difference
and union
, and it'll all be done in a single query:
q1.difference(q2).union(q2.difference(q1))
Upvotes: 0
Reputation: 1432
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
Upvotes: 38
Reputation: 3252
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.
Upvotes: 4
Reputation: 24009
You should be able to use the set operation difference to help:
set(alllists).difference(set(subscriptionlists))
Upvotes: 22
Reputation: 46002
Well I see two options here.
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)
diff = List.objects.filter(datamode = 'A').exclude(member__id=memberid, datamode='A')
Upvotes: 11