有没有办法在 Django Querysets 中组合注释和过滤聚合?

Posted

技术标签:

【中文标题】有没有办法在 Django Querysets 中组合注释和过滤聚合?【英文标题】:Is there a way to combine annotations and filtered aggregations in Django Querysets? 【发布时间】:2019-05-28 12:55:08 【问题描述】:

我有一个复杂的查询,虽然它很容易在 python 代码中完成,但我正在尝试通过 Django Querysets 来完成。

使用来自https://docs.djangoproject.com/en/2.2/topics/db/aggregation/#aggregating-annotations 的示例模型,我要做的是用每位作者的总销售额的平均值来注释每个发布者。但是,每位作者的总销售额应仅包括给定日期范围内的书籍。

有没有办法在一个查询中做到这一点?当然,使用纯 Python 执行两个单独的查询并连接结果是可行的。但是,在我的特定用例中,每个数据库连接/断开连接都会产生大量开销,因此最好将它们组合到一个查询中。此外,真实数据集非常大,因此在服务器端完成聚合至关重要。

这是我期望的 json 输出示例:

"publishers": [ "name": "testpublisher", "avg_recent_sales": "11.2" , "name": "anotherpublisher", "avg_recent_sales": "2.4" ]

其中avg_recent_sales 是过去 6 个月内每位作者通过该出版商销售的平均图书数量。

【问题讨论】:

先过滤。 Book.objects.filter(publication_date__lt=last_date).annotate(...).aggregate(...) 【参考方案1】:

Django 查询集是惰性的。您可以根据需要进行多次过滤或注释,直到您对其进行迭代(例如将其放入“for”或将其转换为“list”)

我已将“sold_amount”添加到 Book 模型中。

books = Book.objects.filter(pubdate__range=(date1, date2))  # filter by given date range.
books = books.values('publisher__id', 'authors__id')  # create group by clause.
books = books.annotate(total_sale_per_author=Avg(F('sold_amount') * F('price')))  # add an annotation.

books = list(book)  # query will be occured here

【讨论】:

啊,但是你看,那你是在给书籍添加注释。我需要注释每个发布者,这似乎只能通过某种形式的嵌套注释来实现。 我希望从查询中看到你想要的数据的 json。 类似于: "publishers": [ "name": "testpublisher", "avg_recent_sales": "11.2" , "name": "anotherpublisher", "avg_recent_sales": "2.4" ] 其中avg_recent_sales 是过去 6 个月内每位作者通过该出版商销售的平均图书数量。 你还应该提供你的模型,因为你引用的模型没有关于每本书通过每个出版商的销售量的数据

以上是关于有没有办法在 Django Querysets 中组合注释和过滤聚合?的主要内容,如果未能解决你的问题,请参考以下文章

Django 不返回QuerySets的API

django不返回QuerySets的API

python Django:QuerySets

Django QuerySets - 如何注释一个字段但返回另一个字段?

如何测试 Django QuerySets 是不是相等?

使用 Django QuerySets 时使用列表推导而不是 for 循环