对多个模型的聚合 - Django
我正在尝试计算一个字段在不同子集上的平均值。
Player.objects.order_by('-score').filter(sex='male').aggregate(Avg('level'))
这个方法运行得很好!
但是……如果我想计算前50名玩家的平均值,就不行了。
Player.objects.order_by('-score').filter(sex='male')[:50].aggregate(Avg('level'))
最后这个查询返回的结果和上面的查询完全一样,这显然是不对的。
我哪里出错了呢?
非常感谢任何帮助!
3 个回答
-1
嗯,文档上说
“切片。正如在限制查询集中的解释,查询集可以使用Python的数组切片语法进行切片。通常,切片一个查询集会返回另一个(未执行的)查询集,但如果你在切片语法中使用了‘步长’参数,Django会执行数据库查询。” http://docs.djangoproject.com/en/dev/ref/models/querysets/
所以我会试试
Player.objects.order_by('-score').filter(sex='male')[0:50:1].aggregate(Avg('level'))
3
把这个问题分成两个简单的步骤来解决:首先确定你想要的数据集合,然后进行汇总计算。
top50_male_players = Player.objects.filter(sex='male').order_by('-score')[:50]
result = Player.objects.filter(pk__in=top50_male_players).aggregate(Avg('level'))
由于QuerySet的懒惰计算特性,这个操作会在数据库中只执行一次。你可以在命令行中试着运行这个查询,看看结果的数量。
> from django.db import connection
> connection.queries = []
> top50_male_players = Player.objects.filter(sex='male').order_by('-score')[:50]
> len(connection.queries)
0
> result = Player.objects.filter(pk__in=top50_male_players).aggregate(Avg('level'))
> len(connection.queries)
1
> result
{'level__avg': <some number>}
> len(connection.queries)
1
4
topfifty = Player.objects.order_by('-score')[:50]
Player.objects.filter(sex='male',pk__in=topfifty).aggregate(avglevel=Avg('level'))
补充:我还没有测试这个,不过我想你能明白我的意思。
topfifty = Player.objects.order_by('-score')[:50]
ids = []
for t in topfifty:
ids += [t.id]
Player.objects.filter(sex='male',pk__in=ids).aggregate(avglevel=Avg('level'))
这有点像是变通的方法,但这是我能想到的最好办法。也许可以考虑先筛选出男性,然后再取前50个男性,而不是先取前50个再去掉男性。