2013-01-07 9 views
7

mam w models.py:scalić querysets w Django

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())) 

Jak mogę napisać tę samą metodę get_all_players, ale powrót QuerySet, nie list?

P.S. Wiem, że jest | operator:

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

Ale działa w bardzo dziwny sposób. Wynik tej funkcji zawiera więcej graczy niż istnieje w players1 + players2 (wynik zawiera powtórzenia niektórych graczy)

Odpowiedz

10

To powinno załatwić sprawę:

# 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 opisany jest szczegółowo tutaj: Complex lookups with Q objects.

+0

Dziękuję bardzo! Nie wiedziałem, że 'games1' w' Q' będzie iterować wszystkie gry. Powiedz mi, dlaczego używasz 'games1__pk = self.pk' zamiast' games1 = self'? Czy są w ten sposób jakieś zalety? – imkost

+0

@imkost: Jestem do tego przyzwyczajony. Wierzę, że 'games1 = self' może być niejawnie przetłumaczone na' games1__pk = self.pk' (jeśli daje taki sam wynik). Posiadanie '__' w nazwie argumentu również wyjaśnia, że ​​w zapytaniu jest zaangażowanych' JOIN'. – Tadeck

11

przypadku może bardziej semantycznie klarownego roztworu:

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

To zdecydowanie bardziej czyste rozwiązanie. –