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):