将Django Count()与条件查找类型一起使用

时间:2013-10-23 23:45:53

标签: mysql sql django python-2.7 django-models

所以我正在尝试聚合考试数据,因为数据库存在于另一台服务器上,我试图将其减少到尽可能少的数据库调用。

我有这个模型(如果重要的话,其对应的表位于mySQL数据库中):

class Exam(models.Model):
    submitted              = models.BooleanField(default=False)
    score                  = models.DecimalField(default=Decimal(0))

这个查询:

>>> exam_models.Exam.objects\
...     .using("exam_datebase")\
...     .aggregate(average=Avg("score"),
...                total=Count("submitted"))
{'average': 22.251082, 'total': 231}

我正在寻找的是一种方法来检索通过的考试数量,其中包括以下内容:

>>> exam_models.Exam.objects\
...     .using("exam_datebase")\
...     .aggregate(average=Avg("score"),
...                total=Count("submitted"))
...                passed=Count("score__gte=80"))
{'average': 22.251082, 'total': 231, 'passed': 42}

我知道我可以使用.filter(score__gte=80).count()发送另一个查询,但我真的希望在同一聚合上获得总计数和传递计数。有什么想法吗?

1 个答案:

答案 0 :(得分:1)

您要么需要两个查询,要么手动进行聚合。

要了解原因,让我们考虑Django生成并用于查询数据库的基础SQL。

Exam.objects.aggregate(average=Avg("score"), total=Count("submitted"))  

大致翻译为

SELECT AVG(score), COUNT(submitted)
FROM exam

聚合的“Count”部分应用于底层sql查询中的SELECT子句。但是,如果我们只想包含大于某个值的分数,则SQL查询需要看起来像这样:

SELECT AVG(score), COUNT(submitted)
FROM exam
WHERE score > 80

使用特定“得分”过滤考试适用于基础SQL语句的WHERE或HAVING子句。

不幸的是,没有办法将这两件事结合起来。所以,你被困在做两个查询。

说了这么多,如果你真的想做一个查询,一个选项就是在你的python代码中进行聚合:

exams = Exam.objects.all()
total_score = 0
total_submitted = 0
passed = 0
for exam in exams:
    total_score += exam.score
    if exam.submitted:
        total_submitted += 1
    if exam.score >= 80:
        passed += 1
exam_aggregates = {
    'average': total_score / len(exams),
    'submitted': total_submitted,
    'passed': passed,
}