diff --git a/atlas/models.py b/atlas/models.py index 0934bbc9..3759d2b6 100644 --- a/atlas/models.py +++ b/atlas/models.py @@ -720,11 +720,20 @@ class Case(models.Model, AuthorMixin, QuestionMixin): series_qs = self.series.all() if exclude_series_ids is not None: - series_qs = self.series.exclude(id__in=exclude_series_ids) - images = [ - [image.image.url for image in series.images.filter(removed=False)] - for series in series_qs.order_by('seriesdetail__sort_order').prefetch_related('images') - ] + series_qs = series_qs.exclude(id__in=exclude_series_ids) + + # Ensure series are ordered by the through model sort_order + series_list = list(series_qs.order_by('seriesdetail__sort_order').prefetch_related('images')) + + images = [] + for series in series_list: + # If images were prefetched, use the cached list and filter in Python + prefetched = getattr(series, '_prefetched_objects_cache', {}).get('images') + if prefetched is not None: + imgs = [img.image.url for img in prefetched if not getattr(img, 'removed', False)] + else: + imgs = [image.image.url for image in series.images.filter(removed=False)] + images.append(imgs) if as_json: return json.dumps(images) diff --git a/atlas/views.py b/atlas/views.py index 938d814d..ff01dd32 100755 --- a/atlas/views.py +++ b/atlas/views.py @@ -3111,31 +3111,32 @@ def collection_viva(request, pk): # ) #) + # Prefetch and annotate aggressively to avoid N+1 queries in the viva view. + # - Prefetch `case__series` using the ordering from SeriesDetail + # - Prefetch only non-removed images for those series (ordered by position) + # - Prefetch case resources and display sets + from django.db.models import Prefetch as _Prefetch + + series_images_qs = SeriesImage.objects.filter(removed=False).order_by("position") + series_qs = Series.objects.order_by("seriesdetail__sort_order").prefetch_related( + _Prefetch("images", queryset=series_images_qs) + ) + casedetails = ( CaseDetail.objects .filter(collection=collection) .select_related("case") .order_by("sort_order") .prefetch_related( - # Prefetch series and their images directly on the case - "case__series", - "case__series__modality", - "case__series__examination", - "case__series__plane", - "case__series__contrast", - "case__series__images", + _Prefetch("case__series", queryset=series_qs), + _Prefetch("case__series__modality"), + _Prefetch("case__series__examination"), + _Prefetch("case__series__plane"), + _Prefetch("case__series__contrast"), + _Prefetch("case__caseresource_set"), + _Prefetch("case__display_sets"), ) - ) - - # Also annotate and prefetch additional related objects used by the viva - # template to avoid N+1 queries when rendering many cases. - casedetails = ( - casedetails .annotate(series_count=Count("case__seriesdetail")) - .prefetch_related( - "case__caseresource_set", - "case__display_sets", - ) )