Python 在Django中跨列聚合
我试图弄清楚是否有一种方法可以使用Django的ORM在Django中进行某种复杂的聚合,或者是否需要使用extra()来插入一些原始SQL 以下是我的对象模型(剥离以显示基本内容): 我想做的是对给定提交的所有投票进行汇总:也就是说,对其任何回复的所有投票,然后还包括将提交标记为最喜欢的人的数量 我让第一部分使用以下代码工作;这将返回每个提交的所有响应的总票数:Python 在Django中跨列聚合,python,django,orm,aggregate,Python,Django,Orm,Aggregate,我试图弄清楚是否有一种方法可以使用Django的ORM在Django中进行某种复杂的聚合,或者是否需要使用extra()来插入一些原始SQL 以下是我的对象模型(剥离以显示基本内容): 我想做的是对给定提交的所有投票进行汇总:也就是说,对其任何回复的所有投票,然后还包括将提交标记为最喜欢的人的数量 我让第一部分使用以下代码工作;这将返回每个提交的所有响应的总票数: submission_list = Response.objects\ .values('submission')\ .an
submission_list = Response.objects\
.values('submission')\
.annotate(votes=Count('voted_up_by'))\
.filter(votes__gt=0)\
.order_by('-votes')[:TOP_NUM]
(因此,在获得投票总数后,我将按降序排序,并返回排名靠前的提交,以获得“最佳”列表。)
那部分有效。你有什么办法可以建议在投票中包括赞成每一项提案的人数吗?(为了便于移植,我宁愿避免额外的(),但我认为这可能是必要的,我愿意使用它。)
编辑:在阅读了下面的建议后,我意识到我应该更清楚地描述这个问题。理想的解决方案是允许我按总票数排序(由投票的和受青睐的之和),然后只选择数据库中的前几位。如果不可能,那么我愿意加载每个响应的几个字段,并用Python进行处理;但由于我将处理100000多条记录,因此最好避免这种开销。(还有,对Adam和Dmitry:我很抱歉延迟回复!)一种可能是稍微重新安排您当前的查询。如果您尝试以下方法会怎么样:
submission_list = Response.objects\
.annotate(votes=Count('voted_up_by'))\
.filter(votes__gt=0)\
.order_by('-votes')[:TOP_NUM]
submission_list.query.group_by = ['submission_id']
这将返回响应对象的查询集(具有相同提交的对象将集中在一起)。为了访问相关提交和/或列表/计数的收藏夹,您有两个选项:
num_votes = submission_list[0].votes
submission = submission_list[0].submission
num_favorite = submission.favorite_of.count()
或者
基本上,第一个选项的好处是仍然是一个queryset,但是您必须确保访问submission对象,以便获得关于提交的任何信息(因为queryset中的每个对象在技术上都是一个响应)。第二个选项的好处是,它是一个包含最喜欢的列表和投票的提交列表,但它不再是一个查询集(因此请确保以后不再需要更改查询)。一种可能是稍微重新安排当前查询。如果您尝试以下方法会怎么样:
submission_list = Response.objects\
.annotate(votes=Count('voted_up_by'))\
.filter(votes__gt=0)\
.order_by('-votes')[:TOP_NUM]
submission_list.query.group_by = ['submission_id']
这将返回响应对象的查询集(具有相同提交的对象将集中在一起)。为了访问相关提交和/或列表/计数的收藏夹,您有两个选项:
num_votes = submission_list[0].votes
submission = submission_list[0].submission
num_favorite = submission.favorite_of.count()
或者
基本上,第一个选项的好处是仍然是一个queryset,但是您必须确保访问submission对象,以便获得关于提交的任何信息(因为queryset中的每个对象在技术上都是一个响应)。第二个选项的好处是,它是一个包含收藏列表和投票的提交列表,但它不再是一个查询集(因此请确保以后不再需要更改查询)。您可以在另一个查询中计算收藏,如
favorite_list = Submission.objects.annotate(favorites=Count(favorite_of))
然后添加两个列表中的值:
total_votes = {}
for item in submission_list:
total_votes[item.submission.id] = item.voted_by
for item in favorite_list:
has_votes = total_votes.get(item.id, 0)
total_votes[item.id] = has_votes + item.favorites
我在字典中使用ID,因为提交对象将不相同。如果您需要提交本身,您可以使用一个或多个字典或存储元组(提交、投票),而不仅仅是投票
添加:此解决方案比以前的解决方案更好,因为您只有两个DB请求。您可以在另一个查询中计算收藏夹,如
favorite_list = Submission.objects.annotate(favorites=Count(favorite_of))
然后添加两个列表中的值:
total_votes = {}
for item in submission_list:
total_votes[item.submission.id] = item.voted_by
for item in favorite_list:
has_votes = total_votes.get(item.id, 0)
total_votes[item.id] = has_votes + item.favorites
我在字典中使用ID,因为提交对象将不相同。如果您需要提交本身,您可以使用一个或多个字典或存储元组(提交、投票),而不仅仅是投票
添加:此解决方案比以前的解决方案更好,因为您只有两个DB请求