Refactor exam_take function to use a canonical list of questions for consistent indexing and improved error handling for question navigation
This commit is contained in:
+17
-10
@@ -188,7 +188,16 @@ def exam_take_overview(request, pk, cid=None, passcode=None):
|
||||
)
|
||||
|
||||
|
||||
def exam_take(request, pk: int, sk: int, cid: str| None = None, passcode: str| None = None):
|
||||
def exam_take(request, pk: int, sk: int, cid: str | None = None, passcode: str | None = None):
|
||||
"""Display and handle answers for a single question in a physics exam.
|
||||
|
||||
Behavior and invariants:
|
||||
- Uses a single canonical list of questions (from `exam.get_questions()`) for
|
||||
selection, navigation and sizing so indexes cannot drift.
|
||||
- Validates the incoming question index and raises 404 for invalid values.
|
||||
- Supports candidate (cid) and logged-in user answers.
|
||||
"""
|
||||
|
||||
exam = get_object_or_404(Exam, pk=pk)
|
||||
|
||||
if not exam.active:
|
||||
@@ -198,25 +207,23 @@ def exam_take(request, pk: int, sk: int, cid: str| None = None, passcode: str| N
|
||||
|
||||
cid_user_exam = exam.get_or_create_cid_user_exam(cid=cid, user_user=request.user)
|
||||
|
||||
# Use a single, canonical list of questions for all indexing/navigation
|
||||
# operations to avoid mismatches between different querysets or orderings.
|
||||
# Canonical questions list for consistent indexing/navigation
|
||||
questions = list(exam.get_questions())
|
||||
|
||||
# Validate sk and select the current question
|
||||
# Normalize and validate provided index
|
||||
try:
|
||||
sk = int(sk)
|
||||
index = int(sk)
|
||||
except Exception:
|
||||
raise Http404("Invalid question index")
|
||||
|
||||
if sk < 0 or sk >= len(questions):
|
||||
if index < 0 or index >= len(questions):
|
||||
raise Http404("Question not found in exam")
|
||||
|
||||
question = questions[sk]
|
||||
|
||||
question = questions[index]
|
||||
exam_length = len(questions)
|
||||
|
||||
# Since we're using the canonical list, the positional index is sk.
|
||||
pos = sk
|
||||
# local numeric position equals the validated index
|
||||
pos = index
|
||||
|
||||
if cid is not None:
|
||||
answer = question.cid_user_answers.filter(cid=cid, exam=exam).first()
|
||||
|
||||
Reference in New Issue
Block a user