Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

merge querysets in django

I have in models.py:

class Game(models.Model):
    players1 = models.ManyToManyField(Player, related_name='games1')
    players2 = models.ManyToManyField(Player, related_name='games2')

    def get_all_players(self):
        return list(itertools.chain(self.players1.all(), self.players2.all()))

How can I write same get_all_players method, but return QuerySet, not list?

P.S. I know that there is | operator:

def get_all_players(self):
    return self.players1.all() | self.players2.all()

But it works in a very strange way. Result of this function contains more players than there are in players1 + players2 (result contains repeats of some players)

like image 222
imkost Avatar asked Jan 07 '13 05:01

imkost


People also ask

How do I combine QuerySets in Django?

You can also use the chain() method from the Itertools module, which allows you to combine two or more QuerySets from different models through concatenation. Alternatively, you can use union() to combine two or more QuerySets from different models, passing all=TRUE if you want to allow duplicates.

How do I merge multiple queries in Django?

Use union operator for queryset | to take union of two queryset. If both queryset belongs to same model / single model than it is possible to combine querysets by using union operator. One other way to achieve combine operation between two queryset is to use itertools chain function.

How do I join models in Django?

Join can be done with select_related method: Django defines this function as Returns a QuerySet that will “follow” foreign-key relationships, selecting additional related-object data when it executes its query.

What is Django Q?

Django Q is a native Django task queue, scheduler and worker application using Python multiprocessing.


2 Answers

For a perhaps more semantically clear solution:

def get_all_players(self):
    return (self.players1.all() | self.players2.all()).distinct()
like image 146
linuxhackerman Avatar answered Oct 30 '22 12:10

linuxhackerman


This should do the trick:

# On the top of the file:
from django.db.models import Q

# Game instance method:
def get_all_players(self):
    return Player.objects.filter(Q(games1__pk=self.pk) | Q(games2__pk=self.pk))

Q is described in details here: Complex lookups with Q objects.

like image 22
Tadeck Avatar answered Oct 30 '22 13:10

Tadeck