Refactor exam take functionality to support HTMX for dynamic question loading and navigation
This commit is contained in:
@@ -302,6 +302,77 @@ def exam_take(request, pk: int, sk: int, cid: str | None = None, passcode: str |
|
||||
)
|
||||
|
||||
|
||||
def exam_take_fragment(request, pk: int, sk: int, cid: str | None = None, passcode: str | None = None):
|
||||
"""Return an HTMX partial containing the question form and navigation controls.
|
||||
|
||||
This view mirrors the GET rendering logic of `exam_take` but returns a fragment
|
||||
suitable for being loaded via HTMX into the page. It intentionally does not
|
||||
process POSTs (the main `exam_take` endpoint handles form submissions and
|
||||
redirects) to keep fragment logic focused on rendering.
|
||||
"""
|
||||
|
||||
exam = get_object_or_404(Exam, pk=pk)
|
||||
|
||||
if not exam.active:
|
||||
return exam_inactive(request, context={"exam": exam})
|
||||
|
||||
exam.check_user_can_take(cid, passcode, request.user)
|
||||
|
||||
cid_user_exam = exam.get_or_create_cid_user_exam(cid=cid, user_user=request.user)
|
||||
|
||||
# Canonical questions list for consistent indexing/navigation
|
||||
questions = list(exam.get_questions())
|
||||
|
||||
try:
|
||||
index = int(sk)
|
||||
except Exception:
|
||||
raise Http404("Invalid question index")
|
||||
|
||||
if index < 0 or index >= len(questions):
|
||||
raise Http404("Question not found in exam")
|
||||
|
||||
question = questions[index]
|
||||
exam_length = len(questions)
|
||||
pos = index
|
||||
|
||||
if cid is not None:
|
||||
answer = question.cid_user_answers.filter(cid=cid, exam=exam).first()
|
||||
else:
|
||||
answer = question.cid_user_answers.filter(user=request.user, exam=exam).first()
|
||||
|
||||
if answer is not None:
|
||||
form = UserAnswerForm(instance=answer)
|
||||
saved_answer = [answer.a, answer.b, answer.c, answer.d, answer.e]
|
||||
else:
|
||||
form = UserAnswerForm()
|
||||
saved_answer = False
|
||||
|
||||
previous = -1
|
||||
if sk > 0:
|
||||
previous = sk - 1
|
||||
next = sk + 1
|
||||
if sk == exam_length - 1:
|
||||
next = False
|
||||
|
||||
return render(
|
||||
request,
|
||||
"physics/partials/exam_take_fragment.html",
|
||||
{
|
||||
"form": form,
|
||||
"cid": cid,
|
||||
"exam": exam,
|
||||
"question": question,
|
||||
"next": next,
|
||||
"previous": previous,
|
||||
"exam_length": exam_length,
|
||||
"pos": pos,
|
||||
"saved_answer": saved_answer,
|
||||
"passcode": passcode,
|
||||
"cid_user_exam": cid_user_exam,
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
# def loadJsonAnswer(answer):
|
||||
# # As access is not restricted make sure the data appears valid
|
||||
# if (not isinstance(answer["cid"], int)) or (not isinstance(answer["eid"], int)):
|
||||
|
||||
Reference in New Issue
Block a user