这就是我想让Django在SQL中生成的内容:
select avg(subquery.countval) from (
select count(something) countval,user_id from foo group by user_id
) subquery
我认为这应该基于Annotated聚合文档与Django一起使用:
Foo.objects.all().values('user_id').\
annotate(countval=Count('id')).\
aggregate(Avg('countval'))
问题是Django 4.x没有生成正确的查询。你会得到类似的东西:
SELECT FROM (SELECT foo.user_id as user_id,COUNT(foo.id)
AS countval from foo
group by foo.user_id)
有什么想法吗?我通过源调试,但不明显出现了什么问题。
答案 0 :(得分:1)
我无法用纯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或ManyToMany关系的所有类完全可重用(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)
如果您计划在数据库中使用大型数据集,则可能需要检查是否存在任何性能差异。