2017-09-04 5 views
0

Il semble que Django ne puisse pas grouper les valeurs après avoir utilisé un filtre avec une expression F(). Par exemple:Django .values ​​() après le filtre d'expression F()

(models.py)

class Athlete(models.Model): 
    name = models.CharField(max_length=30) 
    nationality = models.CharField(max_length=30) 

class TrainingSession(models.Model): 
    training_date = models.DateTimeField() 
    location = models.CharField(max_length=30) 
    athlete = models.ForeignKey(Athlete) 

class Run(models.Model): 
    run_time = models.IntegerField() 
    training = models.ForeignKey(TrainingSession) 

(views.py) Je veux que le nombre de coureurs pour chaque endroit où ils ont eu leur meilleure course.

r = Run.objects.all() 

# Annotate the best time from the training session and filter 
r = r.annotate(best_run_time = Min('trainingsession__run__run_time')) 
r = r.filter(run_time = F('best_run_time')) 

# Group by location 
r = r.values('location') 
r = r.annotate(athlete_count = Count('trainingsession_athlete', distinct=True)) 

Quand je ne pas utiliser l'expression F(), le groupe volonté .values('location') le résultat par emplacement. Cependant, quand je l'utilise, chaque emplacement est donné plusieurs fois avec un athlete_count de 1.

+0

Comment pouvez-vous obtenir "le nombre de coureurs pour chaque endroit où ils ont eu leur meilleure course"? (un seul a best_runtime pour l'emplacement) –

+0

Oui, mais pour un certain endroit, plusieurs coureurs pourraient avoir leur meilleur résultat. – user2621686

+0

Ce que vous ferez Si le temps à deux endroits sera le même pour un athlète? Est-ce que ça devrait le compter dans les deux endroits? Je le pense, juste pour clarifier. –

Répondre

0

Tout d'abord, r.annotate(best_run_time = Min('trainingsession__run__run_time')) annotera un temps différent à chaque objet Run qui n'est pas ce que vous attendez. Vous voulez inclure tout dans le jeu de requête, mais l'annoter le fait pour chaque objet séparément, donc si un objet Run a un run_time de 10 unités, alors 10 est également annoté. Qu'est-ce que vous avez vraiment besoin est aggregate() que vous pouvez utiliser comme ceci:

><> best = Run.objects.all().aggregate(Min('run_time')) 
><> best 
>>> {'run_time__min': 10} 

Votre requête pourrait fonctionner comme ceci:

Il y a quelques problèmes avec Django QuerySets lors de l'utilisation F, les annotations et le filtrage, mais sans savoir quelle version de Django vous utilisez, il est difficile de vous orienter dans la bonne direction.