Refactor exam review response handling to include structured items with optional per-part breakdown for multi-part answers

This commit is contained in:
Ross
2025-11-10 13:08:24 +00:00
parent f3a0a9fd8a
commit bd71c669f0
2 changed files with 61 additions and 8 deletions
+41 -4
View File
@@ -518,10 +518,47 @@ def exam_review_question_summary(request, pk: int, q_index: int):
for k in counts.keys():
pcts[k] = 0.0
# Provide an explicit iterable of (key, count) pairs for templates to consume.
# This avoids relying on attribute-resolution like `exam_response_counts.items`
# in templates which can be ambiguous in Django's template variable lookup.
exam_response_items = sorted(counts.items(), key=lambda x: x[1], reverse=True)
# Provide an explicit iterable of structured items for templates to consume.
# Each item includes the original key, count, pct and optional per-part
# breakdown (list of {value, is_correct}) for physics multi-part answers.
exam_response_items = []
parts_names = ["a", "b", "c", "d", "e"]
for k, v in sorted(counts.items(), key=lambda x: x[1], reverse=True):
item = {"key": k, "count": v, "pct": pcts.get(k, 0.0), "parts": None}
# Attempt to parse comma-separated boolean-like keys into parts
try:
if isinstance(k, str) and "," in k:
parts_raw = [p.strip() for p in k.split(",")]
if len(parts_raw) == 5:
parts_details = []
for idx, sval in enumerate(parts_raw):
sval_l = sval.lower()
if sval_l in ("true", "t", "1", "yes"):
val = True
elif sval_l in ("false", "f", "0", "no"):
val = False
elif sval_l in ("none", "", "not answered", "not_answered"):
val = None
else:
# leave as string fallback
val = sval
# determine correctness where possible
is_correct = None
try:
correct_val = getattr(question, f"{parts_names[idx]}_answer")
if isinstance(val, bool) and isinstance(correct_val, bool):
is_correct = val == correct_val
except Exception:
is_correct = None
parts_details.append({"value": val, "is_correct": is_correct})
item["parts"] = parts_details
except Exception:
item["parts"] = None
exam_response_items.append(item)
# Compute percent correct using per-answer scoring
correct_count = None