F()表达式过滤后的Django .values()

时间:2017-09-04 09:19:43

标签: python django django-queryset

使用带有F()表达式的过滤器后,似乎Django无法对值进行分组。例如:

(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) 我希望每个位置都有最佳跑步者的跑步者数量。

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

当我不使用F()表达式时,.values('location')会按位置对结果进行分组。但是,当我使用它时,每个位置都会被赋予一个Athle_count为1的多次。

1 个答案:

答案 0 :(得分:0)

首先,r.annotate(best_run_time = Min('trainingsession__run__run_time'))将为每个Run对象注释不同的时间,这不是您所期望的。您希望在查询集中包含所有内容,但是注释会为每个对象单独进行注释,因此如果Run对象的run_time为10个单位,则10也会进行注释。您真正需要的是aggregate(),您可以这样使用:

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

您的查询可以这样工作:

Run.objects.filter(run_time=best['run_time__min']).values('location')  

使用F,注释和过滤时,Django查询集存在一些问题,但是如果不知道您使用的是哪个Django版本,则很难指出正确的方向。