2010-03-07 51 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在詞典中,因爲提交的對象不會是相同的。如果您自己需要提交作品,您可以使用更多字典或存儲元組(提交,投票)而不是僅投票。

增加:這個解決方案比以前更好,因爲你只有兩個數據庫請求。