From b424defd57d167a76ca6420a243ba2dac66a02cc Mon Sep 17 00:00:00 2001 From: Ross Date: Fri, 7 Nov 2025 22:16:24 +0000 Subject: [PATCH] Optimize exam collection queries by annotating exam counts and prefetching authors to improve template performance --- .../generic/examcollection_list.html | 10 +++---- generic/views.py | 26 ++++++++++++++++++- 2 files changed, 29 insertions(+), 7 deletions(-) diff --git a/generic/templates/generic/examcollection_list.html b/generic/templates/generic/examcollection_list.html index 5f2f1743..91660075 100755 --- a/generic/templates/generic/examcollection_list.html +++ b/generic/templates/generic/examcollection_list.html @@ -27,12 +27,10 @@ Archived {% endif %} - {# Total exams count (sum of known related exam sets) #} - {% with a=collection.anatomy_exams.count l=collection.longs_exams.count p=collection.physics_exams.count r=collection.rapids_exams.count s=collection.sbas_exams.count %} - {% with total=a|add:l|add:p|add:r|add:s %} - {{ total }} exams - {% endwith %} - {# Per-type badges (only show non-zero) #} + {# Use annotated counts provided by the view to avoid per-card COUNT queries #} + {{ collection.total_count }} exams + {# Per-type badges (only show non-zero) #} + {% with a=collection.anatomy_count l=collection.longs_count p=collection.physics_count r=collection.rapids_count s=collection.sbas_count %} {% if a %}Anatomy {{ a }}{% endif %} {% if l %}Longs {{ l }}{% endif %} {% if p %}Physics {{ p }}{% endif %} diff --git a/generic/views.py b/generic/views.py index ca86f9b9..2bba6213 100644 --- a/generic/views.py +++ b/generic/views.py @@ -67,7 +67,7 @@ from generic.mixins import CheckCanEditMixin, SuperuserRequiredMixin import zipfile from django.core.files.base import ContentFile -from django.db.models import Q +from django.db.models import Q, Count, F from .forms import ( CidGroupExamForm, @@ -4777,6 +4777,30 @@ class SupervisorList(CidManagerRequiredMixin, SingleTableMixin, FilterView): class ExamCollectionList(ListView): model = ExamCollection + + def get_queryset(self): + """Annotate exam counts per collection and prefetch authors to avoid N+1 queries in templates.""" + qs = ( + ExamCollection.objects.all() + .annotate( + anatomy_count=Count("anatomy_exams", filter=Q(anatomy_exams__archive=False)), + longs_count=Count("longs_exams", filter=Q(longs_exams__archive=False)), + physics_count=Count("physics_exams", filter=Q(physics_exams__archive=False)), + rapids_count=Count("rapids_exams", filter=Q(rapids_exams__archive=False)), + sbas_count=Count("sbas_exams", filter=Q(sbas_exams__archive=False)), + ) + .annotate( + total_count=F("anatomy_count") + +F("longs_count") + +F("physics_count") + +F("rapids_count") + +F("sbas_count") + ) + .prefetch_related("author") + .order_by("name") + ) + + return qs class ExamCollectionDetail(DetailView, AuthorRequiredMixin):