From 3e1cb4b54fdd90c463049d84bd58582108e52fd0 Mon Sep 17 00:00:00 2001 From: Ross Date: Mon, 29 Dec 2025 12:09:18 +0000 Subject: [PATCH] Optimize question loading and user answer retrieval in ExamViews to reduce database queries --- generic/views.py | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/generic/views.py b/generic/views.py index 2366128f..7ac114d6 100644 --- a/generic/views.py +++ b/generic/views.py @@ -3436,29 +3436,30 @@ class ExamViews(View, LoginRequiredMixin): if user is None: user = request.user - questions = ( - exam.get_questions() - ) # .prefetch_related("cid_user_answers", "answers") + # Load questions; prefetch 'answers' for apps that use them to avoid repeated DB hits + questions_qs = exam.get_questions() + if self.app_name not in ("physics",): + questions_qs = questions_qs.prefetch_related("answers") - # cid_user_answers = list(UserAnswer.objects.filter(cid=cid, exam__id=pk).prefetch_related("question")) + # Materialize questions list for iteration + questions = list(questions_qs) - # cid_user_answers_q_map = {} + # Fetch all relevant UserAnswer objects up-front to avoid per-question queries + if cid is not None: + user_answers_qs = self.UserAnswer.objects.filter(cid=cid, exam__id=pk).select_related("question") + else: + user_answers_qs = self.UserAnswer.objects.filter(user=user, exam__id=pk).select_related("question") - # for ans in cid_user_answers: - # cid_user_answers_q_map[ans.question] = ans + # Map question_id -> UserAnswer for O(1) lookup + user_answers_map = {ua.question_id: ua for ua in user_answers_qs} answers_and_marks = [] answers_marks = [] answers = [] for q in questions: - # Get user answer - if cid is not None: - user_answer = q.cid_user_answers.filter(cid=cid, exam__id=pk).first() - else: - user_answer = q.cid_user_answers.filter( - user=request.user, exam__id=pk - ).first() + # Get user answer from the in-memory map (avoids N+1 queries) + user_answer = user_answers_map.get(q.pk) # user_answer = cid_user_answers_q_map[q] feedback = None