我有以下型号:
人物模型与问题有很多对话(M2M)。
class Person(models.Model):
name = models.CharField(max_length=100)
questions = models.ManyToManyField(Question, related_name='persons')
我从Django调试工具栏中看到,当我发出:
时persons = Person.objects.filter(name="Foo").prefetch_related("questions")
它执行2个查询,一个到Person表,另一个到Questions表作为例外。
但是,如果我遍历模板中的列表,则会对每行Person进行额外的选择查询。
{% for person in persons %}
{{ person.name }}
{% for question in person.questions.all %}
{{ question.text }}
{% endfor %}
{% endfor %}
这是问题的第二个SQL,所以肯定prefetch正在工作,但不知何故它需要额外的查询来显示每个问题。
SELECT ("myapp_person_questions"."person_id") AS "_prefetch_related_val",
"myapp_question"."id", "myapp_question"."asker_id",
"myapp_question"."question", "myapp_question"."timestamp"
INNER JOIN "myapp_person_questions" ON ("myapp_question"."id" =
"myapp_person_questions"."question_id") WHERE
"myapp_person_questions"."person_id" IN (1, 2, 3, 4) ORDER BY
"myapp_question"."timestamp" DESC
SELECT "myapp_question"."id", "myapp_question"."asker_id",
"myapp_question"."question", "myapp_question"."timestamp" FROM
"myapp_question" INNER JOIN "myapp_person_questions"
ON ("myapp_question"."id" = "myapp_person_questions"."question_id")
WHERE "myapp_person_questions"."person_id" = 1 ORDER BY "myapp_question"."timestamp" DESC
我已停用所有自定义Manager
,因此我非常确定QuerySet
上没有进行其他过滤。
有一点需要注意的是,我自己没有明确生成连接表,这可能是问题吗? (使用through
)
答案 0 :(得分:0)
我遇到了同样的问题:每当我尝试引用我认为已经在查询中撤回的内容时,我正在执行其他查询!我想我找到了解决方案。为了防止对每个实例进行额外查找,您可以扩展prefetch_related以包含所需的查找表。实际上,这会产生一个查询,但它不会产生10,000个查询,假设您有10,000个人正在尝试访问。
students = Person.objects.select_related('gender',
'old_race',
'ethnicity',
'father_education_level',
'mother_education_level',
).prefetch_related('personethnicity_set',
'personethnicity_set__ethnicity',
'studentsemester_set',
'studentsemester_set__semester',
'studentsemester_set__first_mode_admission',
'studentsemester_set__classification',
'studentsemester_set__academic_status',
'studentsemester_set__studentsemestermajor_set',
'studentsemester_set__studentsemestermajor_set__major_type',
'studentsemester_set__studentsemestermajor_set__major',
'studentsemester_set__studentsemestermajor_set__major__registrar_school').filter(ftic_cohort=oursem).order_by('-studentsemester__semester__ccyys')
在上面的代码中,我能够使用select_related获取我的人员记录的所有查找表(一对一)。然后,我能够使用prefetch_related(personethnicity和studentsemester),和来获取我的多个manys,我能够获得与那些多对多表一起使用的查找表。做人性,有同情心等等。
在一个回收8000名学生的查询中,我只使用此代码执行15次SQL查询。然后我通过这样做来引用我的预取字段(在我的例子中,在学生中的一个循环中):
studict['ethnicities'] = ''
for myeth in stud.personethnicity_set.all():
studict['ethnicities'] += str(myeth.ethnicity) + ' '
希望这有帮助。