2

因此,我正在尝试汇总考试数据,并且由于数据库位于另一台服务器上,因此我试图将其减少到尽可能少的数据库调用。

我有这个模型(如果重要的话,其对应的表在 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(),但我真的希望在同一个聚合上同时获得总计数和传递计数。有任何想法吗?

4

1 回答 1

1

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

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

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

大致翻译为

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

聚合的“计数”部分应用于基础 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,
}
于 2013-10-24T20:25:34.823 回答