我正在使用Django 1.7,我正试图抓住ORM中新功能的优势。
假设我有:
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'))
使用实际回答的问题列表进行会话。
但是我不能对这些进行聚合,以获取-e.g.-元素的数量:
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
或类似的东西(因为在分组字段中存在功能依赖性,我将收集用户数据并计算相关的答案项,假设条件通过)。所以RAW查询不适合我。
这个想法是为用户提供总积分。
我可以用两种方式(或两种方式)回答我的问题。
答案 0 :(得分:0)
我不相信使用预取会在这种情况下获得任何好处。通常,prefetch_related和select_related用于循环过滤器集并访问每个过滤器集的相关对象。通过在初始查询中进行注释,我相信django会为您进行优化。
对于“让每个用户注释了他们的”点的问题“尝试此查询:
Player.objects.annotate(total_right=models.Count('games__questions__right'))