Skip to content

Commit 941909b

Browse files
committed
Fix Active Dref Operations List n+1 query issue (active-dref)
1 parent 61b8481 commit 941909b

2 files changed

Lines changed: 64 additions & 12 deletions

File tree

dref/serializers.py

Lines changed: 46 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -252,24 +252,41 @@ class Meta:
252252

253253
@extend_schema_field(MiniOperationalUpdateActiveSerializer(many=True))
254254
def get_operational_update_details(self, obj):
255-
queryset = DrefOperationalUpdate.objects.filter(dref_id=obj.id).order_by("-created_at")
255+
prefetched = getattr(obj, "prefetched_operational_updates", None)
256+
queryset = prefetched if prefetched is not None else obj.drefoperationalupdate_set.order_by("-created_at")
256257
return MiniOperationalUpdateActiveSerializer(queryset, many=True).data
257258

258259
@extend_schema_field(MiniDrefFinalReportActiveSerializer)
259260
def get_final_report_details(self, obj):
260-
queryset = DrefFinalReport.objects.filter(dref_id=obj.id).first()
261-
return MiniDrefFinalReportActiveSerializer(queryset).data
261+
prefetched = getattr(obj, "prefetched_final_report", None)
262+
if prefetched is not None:
263+
if isinstance(prefetched, list):
264+
final_report = prefetched[0] if prefetched else None
265+
else:
266+
final_report = prefetched
267+
else:
268+
try:
269+
final_report = obj.dreffinalreport
270+
except DrefFinalReport.DoesNotExist:
271+
final_report = None
272+
if final_report is None:
273+
return None
274+
return MiniDrefFinalReportActiveSerializer(final_report).data
262275

263276
def get_has_ops_update(self, obj) -> bool:
264-
op_count_count = obj.drefoperationalupdate_set.count()
265-
if op_count_count > 0:
266-
return True
267-
return False
277+
prefetched = getattr(obj, "prefetched_operational_updates", None)
278+
if prefetched is not None:
279+
return len(prefetched) > 0
280+
return obj.drefoperationalupdate_set.exists()
268281

269282
def get_has_final_report(self, obj) -> bool:
270-
if hasattr(obj, "dreffinalreport"):
271-
return True
272-
return False
283+
prefetched = getattr(obj, "prefetched_final_report", None)
284+
if prefetched is not None:
285+
return bool(prefetched)
286+
try:
287+
return obj.dreffinalreport is not None
288+
except DrefFinalReport.DoesNotExist:
289+
return False
273290

274291
def get_application_type(self, obj) -> str:
275292
return "DREF"
@@ -278,10 +295,28 @@ def get_application_type_display(self, obj) -> str:
278295
return gettext("DREF application")
279296

280297
def get_unpublished_op_update_count(self, obj) -> int:
298+
prefetched = getattr(obj, "prefetched_operational_updates", None)
299+
if prefetched is not None:
300+
return sum(1 for op in prefetched if op.status != Dref.Status.APPROVED)
281301
return DrefOperationalUpdate.objects.filter(dref_id=obj.id).exclude(status=Dref.Status.APPROVED).count()
282302

283303
def get_unpublished_final_report_count(self, obj) -> int:
284-
return DrefFinalReport.objects.filter(dref_id=obj.id).exclude(status=Dref.Status.APPROVED).count()
304+
prefetched = getattr(obj, "prefetched_final_report", None)
305+
if prefetched is not None:
306+
if isinstance(prefetched, list):
307+
if not prefetched:
308+
return 0
309+
final_report = prefetched[0]
310+
else:
311+
final_report = prefetched
312+
if final_report is None:
313+
return 0
314+
return 0 if final_report.status == Dref.Status.APPROVED else 1
315+
try:
316+
final_report = obj.dreffinalreport
317+
except DrefFinalReport.DoesNotExist:
318+
return 0
319+
return 0 if final_report.status == Dref.Status.APPROVED else 1
285320

286321

287322
class PlannedInterventionSerializer(

dref/views.py

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import django.utils.timezone as timezone
66
from django.contrib.auth.models import Permission
77
from django.db import models, transaction
8+
from django.db.models import Prefetch
89
from django.http import HttpResponse
910
from django.templatetags.static import static
1011
from django.utils.translation import gettext
@@ -345,7 +346,23 @@ class ActiveDrefOperationsViewSet(viewsets.ReadOnlyModelViewSet):
345346
permission_classes = [permissions.IsAuthenticated, DenyGuestUserPermission]
346347
filterset_class = ActiveDrefFilterSet
347348
queryset = (
348-
Dref.objects.prefetch_related("planned_interventions", "needs_identified", "national_society_actions", "users")
349+
Dref.objects.select_related("country")
350+
.prefetch_related(
351+
"planned_interventions",
352+
"needs_identified",
353+
"national_society_actions",
354+
"users",
355+
Prefetch(
356+
"dreffinalreport",
357+
queryset=DrefFinalReport.objects.all(),
358+
to_attr="prefetched_final_report",
359+
),
360+
Prefetch(
361+
"drefoperationalupdate_set",
362+
queryset=DrefOperationalUpdate.objects.order_by("-created_at"),
363+
to_attr="prefetched_operational_updates",
364+
),
365+
)
349366
.order_by("-created_at")
350367
.filter(is_active=True)
351368
.distinct()

0 commit comments

Comments
 (0)