2011-10-25 29 views
51

Załóżmy, że mam coś takiego w moim models.py:Django filtruje model w liczniku ManyToMany?

class Hipster(models.Model): 
    name = CharField(max_length=50) 

class Party(models.Model): 
    organiser = models.ForeignKey() 
    participants = models.ManyToManyField(Profile, related_name="participants") 

Teraz w moim views.py chciałbym zrobić kwerendę, która będzie pobierał imprezę dla użytkownika, gdzie znajduje się więcej niż 0 uczestnicy.

Coś takiego może:

user = Hipster.get(pk=1) 
hip_parties = Party.objects.filter(organiser=user, len(participants) > 0) 

Jaki jest najlepszy sposób to zrobić?

+21

+1 tylko do tworzenia obiektu 'Hipster'. Zbyt śmieszne. – jathanism

+2

+1 dla wspaniałych lekcji, ale także zwięzłe pytanie ... – bhell

Odpowiedz

92

Jeśli to działa, to w jaki sposób bym to zrobił.

Najlepszy sposób może oznaczać wiele rzeczy: najlepszą wydajność, większość możliwości konserwacji itd. Dlatego nie powiem, że jest to najlepszy sposób, ale lubię trzymać się funkcji ORM tak bardzo, jak to tylko możliwe, ponieważ wydaje się być łatwiejszy do utrzymania .

from django.db.models import Count 

user = Hipster.objects.get(pk=1) 
hip_parties = (Party.objects.annotate(num_participants=Count('participants')) 
          .filter(organiser=user, num_participants__gt=0)) 
+0

To jest kolejny dobry sposób na zrobienie tego, choć nie tak zwięzły jak wybrana odpowiedź. – jathanism

+11

+1, "więcej niż Y", "mniej niż X" są tutaj uwzględnione, a nie tylko wartość null, która faktycznie odpowiada na pytanie, "Django filtruje model na podstawie ManyToMany" –

+3

To powinno być naprawdę zaakceptowaną odpowiedzią. – gregoltsov

28
Party.objects.filter(organizer=user, participants__isnull=False) 
Party.objects.filter(organizer=user, participants=None) 
+0

Nie sądzę, że jest to najbardziej elegancki z rozwiązań, ale działa w moim przypadku. Będę nadal rozglądał się, czy istnieje jakiś rozsądny sposób robienia tego. – Ska

+0

Co nie jest eleganckie w tym rozwiązaniu? Dokładnie o to prosiłeś! :) Z odpowiedzi nie wynika jednoznacznie, ale używałbyś jednego lub drugiego, a nie obu. Dwa podejścia do tego samego problemu. – jathanism

+0

Bardziej elegancka byłaby oczywiście możliwość bezpośredniego odniesienia się do numeru. null to nie to samo, co len() == 0, czy coś mi brakuje? – Ska

3

łatwiejsze exclude:

# organized by user and has more than 0 participants 
Party.objects.filter(organizer=user).exclude(participants=None) 

również zwraca różne wyniki

0

Oparty @ Yuji-'Tomita'-Tomita odpowiedź Dodałem także .distinct (” id), aby wykluczyć duplikaty rekordów:

Party.objects.filter(organizer=user, participants__isnull=False).distinct('id') 

Dlatego każda ze stron jest wymieniona tylko raz.

Powiązane problemy