From e58f070ae252967054a344d85cb5c22a2948b77e Mon Sep 17 00:00:00 2001 From: Ross Date: Mon, 3 Nov 2025 11:37:09 +0000 Subject: [PATCH] Enhance question review functionality with latest review status annotation and display in templates --- generic/views.py | 40 ++++++++++++++----- sbas/templates/sbas/question_detail.html | 2 +- sbas/templates/sbas/question_review_list.html | 12 ++++++ .../templates/sbas/question_review_start.html | 10 +++++ 4 files changed, 54 insertions(+), 10 deletions(-) diff --git a/generic/views.py b/generic/views.py index 02300386..f67bfcf7 100644 --- a/generic/views.py +++ b/generic/views.py @@ -3199,6 +3199,20 @@ class GenericViewBase: except Exception: pass + # Annotate with latest review status using a DB subquery for efficiency + try: + from django.db.models import OuterRef, Subquery + ct = ContentType.objects.get_for_model(self.question_object) + latest_status_subq = ( + QuestionReview.objects.filter(content_type=ct, object_id=OuterRef("pk")) + .order_by("-created_on") + .values("status")[:1] + ) + qs = qs.annotate(latest_review_status=Subquery(latest_status_subq)) + except Exception: + # annotation failed — we'll fall back to per-object lookup below + pass + # Optionally filter by review status results = [] for question in qs: @@ -3210,19 +3224,15 @@ class GenericViewBase: except Exception: pass - ct = ContentType.objects.get_for_model(question) - latest = ( - QuestionReview.objects.filter(content_type=ct, object_id=question.pk) - .order_by("-created_on").first() - ) - + # Determine latest status — prefer annotated value if present + latest_status = getattr(question, "latest_review_status", None) match = False if status == "ANY": match = True elif status == "UNREVIEWED": - match = latest is None + match = latest_status is None else: - if latest is not None and latest.status == status: + if latest_status is not None and latest_status == status: match = True if match: @@ -3241,7 +3251,19 @@ class GenericViewBase: results.append(question) - return render(request, f"{self.app_name}/question_review_list.html", {"questions": results, "app_name": self.app_name, "filters": {"category": category, "status": status}}) + # Provide human-readable labels for statuses to the template + status_choices = {code: label for code, label in QuestionReview.StatusChoices.choices} + + return render( + request, + f"{self.app_name}/question_review_list.html", + { + "questions": results, + "app_name": self.app_name, + "filters": {"category": category, "status": status}, + "status_choices": status_choices, + }, + ) @method_decorator(user_passes_test(lambda u: u.is_superuser)) diff --git a/sbas/templates/sbas/question_detail.html b/sbas/templates/sbas/question_detail.html index 4d9bf65a..a859ea71 100644 --- a/sbas/templates/sbas/question_detail.html +++ b/sbas/templates/sbas/question_detail.html @@ -96,7 +96,7 @@
Feedback
-
{{ question.feedback|linebreaks }}
+
{{ question.feedback|safe|linebreaks }}
diff --git a/sbas/templates/sbas/question_review_list.html b/sbas/templates/sbas/question_review_list.html index d47dcba6..1ce27501 100644 --- a/sbas/templates/sbas/question_review_list.html +++ b/sbas/templates/sbas/question_review_list.html @@ -1,5 +1,7 @@ {% extends 'sbas/base.html' %} +{% load partials %} + {% block content %}

Filtered questions

@@ -36,6 +38,16 @@
{{ q.title|default:q.stem|truncatechars:80|safe }}
ID: {{ q.pk }}
+ {% comment %} Show latest review status if available {% endcomment %} + {% with status_code=q.latest_review_status %} + {% if status_code %} + {% with label=status_choices|get_item:status_code %} +
Latest review: {{ label }}
+ {% endwith %} + {% else %} +
Latest review: Unreviewed
+ {% endif %} + {% endwith %}
View diff --git a/sbas/templates/sbas/question_review_start.html b/sbas/templates/sbas/question_review_start.html index 1ed49325..9c5bc99c 100644 --- a/sbas/templates/sbas/question_review_start.html +++ b/sbas/templates/sbas/question_review_start.html @@ -25,6 +25,8 @@
+ +
@@ -40,7 +42,13 @@
+ + +
+ + +