2011-10-25 14 views
51

Supongamos que tengo algo como esto en mi models.py:Django filtra el modelo en ManyToMany count?

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

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

Ahora en mi views.py me gustaría hacer una consulta, que se vendería por una de las partes para el usuario, donde hay más de 0 participantes.

Algo como esto quizá:

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

Cuál es la mejor manera de hacerlo?

+21

+1 simplemente para crear un objeto 'Hipster'. Demasiado gracioso. – jathanism

+2

+1 para las grandes clases, pero también la pregunta concisa ... – bhell

Respuesta

92

Si esto funciona, así es como lo haría.

La mejor manera puede significar muchas cosas: mejor rendimiento, más mantenible, etc. Por lo tanto, no diré que esta es la mejor manera, pero me gusta mantener las características de ORM tanto como sea posible ya que parece más fácil de mantener .

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

Esta es otra buena manera de hacerlo, aunque no tan sucinta como la respuesta elegida. – jathanism

+11

+1, "más que Y", "menos de X" están todos cubiertos aquí, no solo nulo, que en realidad responde a la pregunta, "Django filtra el modelo en el recuento ManyToMany" –

+3

Esta debería ser realmente la respuesta aceptada. – gregoltsov

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

No creo que esta sea la solución más elegante, pero funciona en mi caso. Todavía miraré a mi alrededor si hay alguna forma sensata de hacerlo. – Ska

+0

¿Qué no es elegante acerca de esta solución? ¡Es exactamente lo que pediste! :) No está del todo claro por la respuesta, pero usarías uno o el otro, no los dos. Dos enfoques para el mismo problema. – jathanism

+0

Por supuesto, sería más elegante si se pudiera consultar el número directamente. null no es lo mismo que len() == 0, ¿o me falta algo? – Ska

3

más fácil con exclude:

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

también devuelve resultados distintos

0

Derivados de respuesta @ Yuji-'Tomita'-Tomita, también han añadido .distinct (' id ') para excluir los registros duplicados:

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

Por lo tanto, cada parte aparece solo una vez.

Cuestiones relacionadas