Optimize collection_viva by aggressively prefetching and annotating related objects to prevent N+1 queries
This commit is contained in:
+14
-5
@@ -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)
|
||||
|
||||
+18
-17
@@ -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",
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user