考虑以下模型:
class Question(models.Model):
...
class Answer(models.Model):
user = models.ForeignKey('auth.User')
question = models.ForeignKey(Question)
answer = models.TextField(...)
class Meta:
unique_together = ('user', 'question'),
现在在视图中我想迭代一些问题并使用request.user中的(仅可能存在的)答案,如:
questions = Questions.objects.filter(...).iterator()
for q in questions:
try:
a = Answer.objects.get(user=request.user, question=q)
except Answer.DoesNotExist:
a = None
do_something_with(a)
这导致O(#Questions)
数据库命中。我可以使用.prefetch_related(),但我没有看到一种方法来限制使用Answer
预取到user=request.user
的值,并且在拥有大量用户的网站上需要花费相当多的金额用于预取所有用户的答案的内存。
我认为可以使用.extra()在单个查询中检索信息。我还没有对它进行测试,但我希望以下内容能够正常工作:
questions = Questions.objects.extra(select={'user_answer': 'SELECT id, answer from answer where answer.user.id = %s', }, params=(request.user.id,))
(如果没有可用的答案,不确定这是如何表现的。)
Questions.objects.filter(answer__user=request.user)
无法正常工作,因为它会跳过Answer
之前没有相关request.user
的问题。
还使用两个查询:
questions = Question.objects.filter(...).all()
users_answers = Answer.objects.filter(user=request.user, question__in=questions)
users_answers = dict((a.id, a) for a in users_answers)
for q in questions:
a = users_answers.get(q.id)
如果有许多问题与使用过的过滤器匹配,则效率低下。
是否有更多的pythonic方式不会强迫我编写SQL,更容易编写和读取,并且仍然比逐个获取Answer
的第一个变体更有效在Python循环中?