Add primary answer display to exam review question fragment and ensure safe rendering of question text

This commit is contained in:
Ross
2025-11-10 12:37:13 +00:00
parent e7c15a75a0
commit 744f2c7600
3 changed files with 82 additions and 19 deletions
+78 -18
View File
@@ -1214,15 +1214,44 @@ class ExamViews(View, LoginRequiredMixin):
else:
pcts = {k: 0.0 for k in counts.keys()}
# Compute percent correct where a best_answer exists
# Compute percent correct using per-answer scoring when available.
# Different apps use different scoring scales (e.g. anatomy/rapids=2, longs=8,
# physics/shorts=5, sbas=1). We determine the per-question maximum based on
# the app and count user answers whose get_answer_score() equals that max.
correct_pct = None
correct_count = None
if hasattr(q, "best_answer") and getattr(q, "best_answer", None):
try:
correct_count = ua_qs.filter(answer=q.best_answer).count()
try:
# Determine per-question maximum score for this app
if self.app_name in ("rapids", "anatomy"):
per_question_max = 2
elif self.app_name == "longs":
per_question_max = 8
elif self.app_name in ("physics", "shorts"):
per_question_max = 5
else:
per_question_max = 1
# If we have responses, iterate and count fully-correct answers using
# the model's get_answer_score() which encapsulates per-app logic.
if total_responses:
cnt = 0
for ua in ua_qs:
try:
score = ua.get_answer_score()
except Exception:
# If get_answer_score fails for any answer, skip it
continue
if score == per_question_max:
cnt += 1
correct_count = cnt
correct_pct = round(100.0 * correct_count / total_responses, 1) if total_responses else 0.0
except Exception:
correct_pct = None
else:
correct_count = 0
correct_pct = 0.0
except Exception:
# Best-effort: fall back to None if something unexpected happens
correct_pct = None
correct_count = None
# Percent answered relative to candidate pool (if known)
answered_pct = None
@@ -1343,20 +1372,51 @@ class ExamViews(View, LoginRequiredMixin):
for k in counts.keys():
pcts[k] = 0.0
# If the question exposes a best_answer, compute correct count
# Compute correct count using per-answer scoring when available.
# Different apps use different scoring scales (e.g. anatomy/rapids=2,
# longs=8, physics/shorts=5, sbas=1). Determine per-question max
# and count answers where get_answer_score() equals that max.
correct_count = None
if hasattr(question, "best_answer") and question.best_answer:
correct_count = ua_qs.filter(answer=question.best_answer).count()
else:
correct_count = None
# percent correct
correct_pct = None
if correct_count is not None and total_responses:
try:
correct_pct = round(100.0 * correct_count / total_responses, 1)
except Exception:
correct_pct = None
try:
if self.app_name in ("rapids", "anatomy"):
per_question_max = 2
elif self.app_name == "longs":
per_question_max = 8
elif self.app_name in ("physics", "shorts"):
per_question_max = 5
else:
per_question_max = 1
if total_responses:
cnt = 0
for ua in ua_qs:
try:
score = ua.get_answer_score()
except Exception:
continue
# Handle tuple/list scores (physics) by summing parts
if isinstance(score, (list, tuple)):
try:
ssum = sum([s for s in score if isinstance(s, (int, float))])
except Exception:
continue
if ssum == per_question_max:
cnt += 1
else:
# Numeric scores only; skip 'unmarked' / None
if isinstance(score, (int, float)) and score == per_question_max:
cnt += 1
correct_count = cnt
correct_pct = round(100.0 * correct_count / total_responses, 1) if total_responses else 0.0
else:
correct_count = 0
correct_pct = 0.0
except Exception:
correct_count = None
correct_pct = None
context.update(
{