2014-08-31 61 views
4

我正在使用Django 1.7,並試圖抓住ORM中新功能的優勢。Django 1.7和智能,深度,過濾聚合

假設我有:

class Player(models.Model): 
    name = models.CharField(...) 

class Question(models.Model): 
    title = models.CharField(...) 
    answer1 = models.CharField(...) 
    answer2 = models.CharField(...) 
    answer3 = models.CharField(...) 
    right = models.PositiveSmallIntegerField(...) #choices=1, 2, or 3 

class Session(models.Model): 
    player = models.ForeignKey(Player, related_name="games") 

class RightAnswerManager(models.Manager): 

    def get_queryset(self): 
     super(RightAnswerManager, self).get_queryset().filter(answer=models.F('question__right')) 

class AnsweredQuestion(models.Model): 
    session = models.ForeignKey(Session, related_name="questions") 
    question models.ForeignKey(Question, ...) 
    answer = models.PositiveSmallIntegerField(...) #1, 2, 3, or None if not yet ans. 

    objects = models.Manager() 
    right = RightAnswerManager() 

我知道我可以做:

Session.objects.prefetch_related('questions') 

並獲得有關問題的會議。我

也可以做:

Session.objects.prefetch_related(models.Prefetch('questions', queryset=AnsweredQuestion.right.all(), to_attr='answered')) 

並獲得與實際已回答正確的問題列表中的會話。

我做不到聚集在那些獲得-eg-元素的個數,而不是:

Session.objects.prefetch_related(models.Prefetch('questions', queryset=AnsweredQuestion.right.all(), to_attr='answered')).annotate(total_right=models.Count('answered')) 

因爲answered是不是一個真正的現場:

FieldError: Cannot resolve keyword 'rightones' into field. Choices are: id, name, sessions 

這只是一個樣本,因爲我的模型中有很多字段是我從未包含的。但是這個想法很明確:我無法聚合創建的屬性。

有沒有方法沒有下降到原始迴應以下問題?

Get each user annotated with their "points". 
A user may play any amount of sessions. 
In each session it gets many questions to answer. 
For each right answer, a point is earned. 

在RAW SQL它會是這樣的:

SELECT user.*, COUNT(answeredquestion.id) 
FROM user 
LEFT OUTER JOIN session ON (session.user_id = user.id) 
INNER JOIN answeredquestion ON (answeredquestion.session_id = session.id) 
INNER JOIN question ON (answeredquestion.question_id = question.id) 
WHERE answeredquestion.answer = question.right 
GROUP BY user.id 

或者類似的東西(因爲有在分組字段的功能依賴,我會收集用戶數據並計算相關answeredquestions,假設條件通過)。所以RAW查詢不適合我。

這個想法是讓用戶獲得總積分。

我的問題可以通過兩種方式之一(或兩者)來回答。

  • 是否有執行相同的查詢方式(其實我從來沒有測試這個確切的查詢;它在這裏呈現的想法)與ORM在Django 1.7,莫名其妙地給有關/逆FK預取或經理的選擇字段? 迭代不允許在這裏(我有一個二次版本的N + 1問題!)。
  • 是否有任何django軟件包以某種方式做到這一點?也許是由第三方提供RAW調用的抽象。 這是因爲我會有很多這樣的查詢

回答

0

我不相信使用預取可以在這種情況下獲得任何收益。通常prefetch_related和select_related在遍歷filterset並訪問每個的相關對象時使用。通過在初始查詢中進行註釋,我相信django會爲您優化這個優化。

對於問題點「獲取每個用戶自己的註釋‘’嘗試此查詢:

Player.objects.annotate(total_right=models.Count('games__questions__right'))