2013-10-09 108 views
0

我有以下型號:Django:基於過濾器值計數對象的變化?

class Question(models.Model): 
    question = models.CharField(max_length=100) 
    detail = models.TextField(null=True, blank=True) 

class PossibleAnswers(models.Model): 
    question = models.ForeignKey(Question) 
    value = models.CharField(max_length=200) 

class Answer(models.Model): 
    question = models.ForeignKey(Question) 
    value = models.CharField(max_length=200) 

每個Question已經PossibleAnswers定義由用戶自定義。例如:問題 - 什麼是最好的水果?可能的答案 - 蘋果,橙子,葡萄。現在其他用戶可以將Answer的問題與他們的回覆限制爲PossibleAnswers

我遇到的問題是每個Answer計數。有多少人選擇Apple vs Orange vs Grapes?

Question.answer_set.filter(value="Grapes").count()返回所有葡萄答案的計數,但如果您不知道過濾標準(本例中的葡萄)是什麼?由於用戶定義了答案選項,並且定義了多少種不同的選項,您將如何得到每個答案選項的響應計數?

回答

2

首先,我會改變你的模型。您的模式未規範化。這意味着您可以在多個地方保留相同的信息(答案文本)。這本身被認爲是一件壞事,但也使設計正確的查詢變得更加困難。這就是我想你的模型應該是這樣的:

class Question(models.Model): 
    question = models.CharField(max_length=100) 
    detail = models.TextField(null=True, blank=True) 

class PossibleAnswer(models.Model): 
    question = models.ForeignKey(Question) 
    value = models.CharField(max_length=200) 

class Answer(models.Model): 
    possible_answer = models.ForeignKey(PossibleAnswers) 

用戶每次投票可能的答案,你添加一個新的Answer模型引用該可能的答案。您還可以將其他字段添加到Answer模型中,例如引用用戶投票的外鍵。

那麼你可以使用下面的代碼來獲取信息(即有多少實際的答案,有對每一個可能的答案)的問題foo

PossibleAnswer.objects.filter(question=foo).annotate(Count('answer')) 
+0

+1這真的很好。但是,將模型命名爲問題,回答(而不是可能的答案)和金額或選擇或某物(而不是答案)會不會更好,更清晰?我的意思是在這個模式中,Answer模式的功能類似於投票或Like模式,因爲它只是用於計數 – yuvi

+0

不是,模型名稱應該是單數名詞,描述單個對象,所以我不會考慮「計數」或爲模型選擇一個好名字。但是你是對的,如果我們確信'Answer'模型只用於計數,這將不是最佳解決方案。在這種情況下,我會一起擺脫「Answer」模型,並將「count」字段添加到「PossibleAnswer」模型中(然後確實應該將其重命名爲「Answer」)。每當用戶選擇答案時,該字段應該增加。 –

+0

然而,我並沒有選擇這個解決方案,因爲我認爲很可能有每次用戶投票時應記錄的其他信息,例如時間,用戶名或用戶ip。 –

0

這會幫助你嗎?

q = Question.objects.get(pk=1) 
[{v: q.answer_set.filter(value=v).count()} 
      for v in [pa.value for 
         pa in q.possibleanswers_set.all()]] 

它將返回{「possible_answer」:「數」}的字典存在的問題對象q各自可能的答案。

但是,這是不是做的事情,如果你打算用它在更大的規模上最有效的方式(說的所有問題的對象),在這種情況下,你會好得多使用聚合(閱讀它是here)。

+1

雖然功能性,這可能會對一個相當大的開銷數據庫。 – karthikr

+0

@karthikr你是對的。我已經更新了我的答案 – yuvi

0

你需要一個aggregation query

from django.db.models import Count 
Question.objects.annotate(Count('answer')) 
+0

難道這只是計算**全部**每個問題的答案,而不是爲每個可能的答案提供不同的數字? –