【问题标题】:Using Django Count() with conditional lookup types将 Django Count() 与条件查找类型一起使用
【发布时间】:2013-11-02 11:29:31
【问题描述】:

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

我有这个模型(如果重要的话,其对应的表在 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() 发送另一个查询,但我真的希望在同一个聚合上同时获得总计数和通过计数。有什么想法吗?

【问题讨论】:

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


    【解决方案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,
    }
    

    【讨论】:

    • 这是一个非常有用的解释。当我写这篇文章时,我想我运气不好,但我真的不明白为什么。 Django 的语法有点令人困惑,因为 Count() 使用与 filter() 相同的 __ 语法,但只支持某些查找类型。
    • 您真的应该添加一个免责声明,即 python 聚合是一个糟糕的主意!我想要限制查询的原因是数据库位于不同的服务器上。如果我使用两个查询,我几乎不会通过网络传输任何内容。在另一台服务器上运行 mysql 脚本后,它们各自返回几个 Decimal 对象。如果我使用一个查询并拉取整个表,那么我将通过网络传输大量数据!我还通过将大型查询集强制放入内存而不是存储 3 个十进制值来对 Web 服务器征税!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-01-09
    • 1970-01-01
    • 1970-01-01
    • 2018-12-21
    • 2015-09-12
    相关资源
    最近更新 更多