带注释查询上的Django聚合

带注释查询上的Django聚合,django,orm,annotations,aggregate,Django,Orm,Annotations,Aggregate,这就是我希望Django在SQL中生成的内容: select avg(subquery.countval) from ( select count(something) countval,user_id from foo group by user_id ) subquery 基于带注释的聚合文档,我认为这应该如何与Django配合使用: Foo.objects.all().values('user_id').\ annotate(countval=Coun

这就是我希望Django在SQL中生成的内容:

select avg(subquery.countval) from (
select count(something) countval,user_id from foo group by user_id
 ) subquery
基于带注释的聚合文档,我认为这应该如何与Django配合使用:

Foo.objects.all().values('user_id').\
                 annotate(countval=Count('id')).\
                 aggregate(Avg('countval'))
问题是Django4.x没有生成正确的查询。你会得到这样的结果:

SELECT FROM (SELECT foo.user_id as user_id,COUNT(foo.id) 
 AS countval from foo 
 group by foo.user_id)

有什么想法吗?我通过源代码进行了调试,但不清楚出了什么问题。

我无法使用纯Django代码进行调试,但这是我所能做的最好的了,它尽可能依赖Django代码而不是原始sql

from django.db import connection
from django.db.models import Count

def get_average_count(klass, field_name):
    foo = klass.objects.values(field_name).annotate(countval=Count('id'))
    query = "SELECT AVG(subquery.countval) FROM (%s) subquery" % str(foo.query)
    cursor = connection.cursor()
    cursor.execute(query)
    return float(cursor.fetchone()[0])
这将执行您所说的要生成的SQL语句。它还完全独立于您正在使用的SQL后端,并且对于具有反向ForeignKey或多个关系的所有类都是完全可重用的(yay-DRY)

如果您确实不想使用原始SQL,另一个选项是在Django中计算平均值:

from __future__ import division # no need to cast to float now

def get_average_count(klass, field_name):
    counts = klass.objects.values(field_name).annotate(countval=Count('id')).\
        values_list('countval', flat=True)
    return reduce(lambda x, y: x + y / len(counts), counts, 0)

如果计划在数据库中使用大型数据集,可能需要检查性能差异

简单地说一句:当使用django ORM时,您的order_by()语句已经过时了,因为您没有提供order列…fixed;我在我的真实代码中有一个命令,我正试图清除它