我有两种模式:
class Answer(models.Model):
...
class Photo(models.Model):
name = models.CharField(...)
answer_id = models.Foreignkey(Answer, related_name='photos')
这种关系是一对多的(一个答案有很多照片)
我需要编写一个报告功能,输出所有答案以及相应的照片。这就是我所拥有的:
def report():
answers = Answer.objects.all()
for answer in answers:
result = extract_data(answer)
for photo in answer.photos.all(): # <- executed N times, as N = # of answers in db
result += photo.name + '\r'
append_result_to_report(result)
这样可行,但正如您已经看到的那样,执行for photo in answer.photos.all()
的次数等于数据库中的答案数。
最好,我只想执行两个db查询,一个获取所有答案,另一个获取所有照片。所以我尝试了这个:
def report():
answers = Answer.objects.all()
photos = list(Photo.objects.all()) # <- store the result in memory
for answer in answers:
result = extract_data(answer)
for photo in photos:
if photo.answer_id = answer.id:
result += photo.name + '\r'
append_result_to_report(result)
这种方法将数据库查询的数量减少到两个,但整体执行需要更长的时间。这种方法为9.5秒,第一种方法为7.5秒。
关于如何更有效率的任何建议?
谢谢!
P.S。我正在使用Django 1.8.2
更新:我使用了@Mark Galloway建议的方法,执行时间已降至1.6秒。查询数量变为3. Django执行以下查询:
我想知道上次查询的目的是什么?
答案 0 :(得分:4)
通过使用prefetch_related,您可以走一对多关系,并在两个查询中获取所有照片。一个用于所有答案,另一个用于与答案相关的所有照片。
answers = Answer.objects.all().prefetch_related('photos')
for answer in answers:
result = extract_data(answer)
for photo in answer.photos.all():
result += photo.name + '\r'
append_result_to_report(result)
答案 1 :(得分:-1)
您需要使用select_related
查询修饰符:
def report():
# fetches answers and photos, both, at once
answers = Answer.objects.all().select_related('photos')
for answer in answers:
result = extract_data(answer)
for photo in answer.photos.all():
result += photo.name + '\r'
append_result_to_report(result)