2010-03-07 53 views
1

我想弄清楚是否有办法在Django中使用它的ORM做一个有点复杂的聚合,或者如果我将不得不使用extra()来坚持一些原始SQL。Django中的列汇总

这里是我的对象模型(剥离只显示要领):

class Submission(Models.model) 
    favorite_of = models.ManyToManyField(User, related_name="favorite_submissions") 

class Response(Models.model) 
    submission = models.ForeignKey(Submission) 
    voted_up_by = models.ManyToManyField(User, related_name="voted_up_responses") 

我想要做的就是和所有给定提交的投票:那就是,所有的选票对于任何其答复,然后还包括将提交作为最爱的人数。

我有第一部分工作使用下面的代码;这将返回的总票数为每个提交的所有答复:

submission_list = Response.objects\ 
    .values('submission')\ 
    .annotate(votes=Count('voted_up_by'))\ 
    .filter(votes__gt=0)\ 
    .order_by('-votes')[:TOP_NUM] 

(因此获得了投票总,我按降序排序,并返回顶端TOP_NUM意见后,获得“最佳的”上市)

该部分起作用。您有什么方法可以建议在投票中包含每个提交的受众人数? (我宁愿避免额外()的便携性,但我认为这可能是必要的,我愿意使用它)。

编辑:我意识到阅读后,我应该有在我对这个问题的描述中更加清楚。理想的解决方案是让我按总票数排序(总数为voted_up_byfavorited),然后挑选数据库中的前几名。如果这是不可能的,那么我愿意加载每个响应的一些字段并在Python中进行处理;但由于我将处理100,000多条记录,因此避免这种开销会很好。 (另外,对于亚当和德米特里:我很抱歉在响应中的延迟!)

回答

1

一种可能性是重新安排您当前的查询略有。如果你尝试过类似如下:

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'] 

这将返回响应对象的查询集(具有相同的提交对象将集中在一起)。为了访问相关的提交和/或favorite_of列表/计数,你有两个选择:

num_votes = submission_list[0].votes 
submission = submission_list[0].submission 
num_favorite = submission.favorite_of.count() 

或...

submissions = [] 
for response in submission_list: 
    submission = response.submission 
    submission.votes = response.votes 
    submissions.append(submission) 
num_votes = submissions[0].votes 
submission = submissions[0] 
num_favorite = submission.favorite_of.count() 

基本上第一选项仍然是一个受益queryset,但您必须确保访问提交对象以获取有关提交的任何信息(因为queryset中的每个对象在技术上都是一个Response)。第二个选项的好处是可以同时提供收藏夹列表和投票列表,但它不再是查询集(因此请确保您以后不必再更改查询)。

0

你可以指望在另一个查询的最爱,如

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 

我使用IDS在词典中,因为提交的对象不会是相同的。如果您自己需要提交作品,您可以使用更多字典或存储元组(提交,投票)而不是仅投票。

增加:这个解决方案比以前更好,因为你只有两个数据库请求。