Add HTMX-based response summary and user responses display for exam questions
This commit is contained in:
@@ -80,6 +80,7 @@ from helpers.images import image_as_base64
|
||||
from django.template.defaulttags import register
|
||||
|
||||
from generic.mixins import CheckCanEditMixin, SuperuserRequiredMixin
|
||||
from django.db.models import Count
|
||||
|
||||
|
||||
class AuthorOrCheckerRequiredMixin(object):
|
||||
@@ -259,6 +260,82 @@ def mark(request, exam_pk, sk, unmarked_exam_answers_only=True, review=False):
|
||||
|
||||
n = sk
|
||||
|
||||
|
||||
|
||||
@login_required
|
||||
def exam_review_question_responses(request, pk: int, q_index: int):
|
||||
"""Return the responses partial for a given anatomy exam question (HTMX-friendly)."""
|
||||
exam = get_object_or_404(Exam, pk=pk)
|
||||
|
||||
questions = exam.get_questions()
|
||||
try:
|
||||
question = questions[q_index]
|
||||
except Exception:
|
||||
raise Http404("Question not found in exam")
|
||||
|
||||
try:
|
||||
exam_user_answers = question.cid_user_answers.filter(exam=exam).select_related("user")
|
||||
except Exception:
|
||||
exam_user_answers = question.cid_user_answers.all()
|
||||
|
||||
context = {
|
||||
"exam": exam,
|
||||
"question": question,
|
||||
"q_index": q_index,
|
||||
"app_name": "anatomy",
|
||||
"exam_user_answers": exam_user_answers,
|
||||
}
|
||||
|
||||
return render(request, "anatomy/partials/exam_review_question_responses_fragment.html", context)
|
||||
|
||||
|
||||
@login_required
|
||||
def exam_review_question_summary(request, pk: int, q_index: int):
|
||||
"""Return aggregated response summary partial for anatomy question (HTMX-friendly)."""
|
||||
exam = get_object_or_404(Exam, pk=pk)
|
||||
|
||||
questions = exam.get_questions()
|
||||
try:
|
||||
question = questions[q_index]
|
||||
except Exception:
|
||||
raise Http404("Question not found in exam")
|
||||
|
||||
ua_qs = question.cid_user_answers.filter(exam=exam)
|
||||
total_responses = ua_qs.count()
|
||||
|
||||
# counts by score values ('2','1','0','')
|
||||
score_counts = {}
|
||||
for s, c in ua_qs.values_list("score").annotate(count=Count("id")) if False else []:
|
||||
pass
|
||||
|
||||
# simpler: compute via values
|
||||
score_counts = {row["score"] if row["score"] is not None else "": row["count"] for row in ua_qs.values("score").annotate(count=Count("id"))}
|
||||
|
||||
# top submitted answers (by answer_compare)
|
||||
top_answers = list(ua_qs.values("answer_compare").annotate(count=Count("id")).order_by("-count")[:10])
|
||||
|
||||
correct_count = None
|
||||
correct_pct = None
|
||||
# compute correct based on matching marked answers if available
|
||||
if total_responses:
|
||||
# count scores equal to '2' as correct
|
||||
correct_count = score_counts.get("2", 0)
|
||||
correct_pct = round(100.0 * correct_count / total_responses, 1) if total_responses else None
|
||||
|
||||
context = {
|
||||
"exam": exam,
|
||||
"question": question,
|
||||
"q_index": q_index,
|
||||
"app_name": "anatomy",
|
||||
"exam_response_total": total_responses,
|
||||
"exam_response_score_counts": score_counts,
|
||||
"exam_response_correct_count": correct_count,
|
||||
"exam_response_correct_pct": correct_pct,
|
||||
"top_answers": top_answers,
|
||||
}
|
||||
|
||||
return render(request, "anatomy/partials/exam_review_question_summary_fragment.html", context)
|
||||
|
||||
question_details = {
|
||||
"total": len(questions),
|
||||
"current": n + 1,
|
||||
|
||||
Reference in New Issue
Block a user