From 365db5970268fb007af832812bb519256c3858ba Mon Sep 17 00:00:00 2001 From: Szabo Zoltan Date: Fri, 12 Jun 2026 11:21:00 +0200 Subject: [PATCH] Fix per-assesment n+1 query issue --- per/drf_views.py | 34 ++++++++++++++++++++++++++++++++-- per/serializers.py | 7 +++++++ 2 files changed, 39 insertions(+), 2 deletions(-) diff --git a/per/drf_views.py b/per/drf_views.py index 003d9a55a..b60736383 100644 --- a/per/drf_views.py +++ b/per/drf_views.py @@ -690,7 +690,22 @@ class FormAssessmentViewSet(viewsets.ModelViewSet): ordering_fields = "__all__" def get_queryset(self): - return PerAssessment.objects.select_related("overview") + return PerAssessment.objects.select_related("overview", "overview__country").prefetch_related( + Prefetch( + "area_responses", + queryset=AreaResponse.objects.select_related("area").prefetch_related( + Prefetch( + "component_response", + queryset=FormComponentResponse.objects.select_related("component", "rating").prefetch_related( + Prefetch( + "question_responses", + queryset=FormComponentQuestionAndAnswer.objects.select_related("question"), + ) + ), + ) + ), + ) + ) class PublicFormAssessmentViewSet(viewsets.ReadOnlyModelViewSet): @@ -698,7 +713,22 @@ class PublicFormAssessmentViewSet(viewsets.ReadOnlyModelViewSet): ordering_fields = "__all__" def get_queryset(self): - return PerAssessment.objects.select_related("overview") + return PerAssessment.objects.select_related("overview", "overview__country").prefetch_related( + Prefetch( + "area_responses", + queryset=AreaResponse.objects.select_related("area").prefetch_related( + Prefetch( + "component_response", + queryset=FormComponentResponse.objects.select_related("component", "rating").prefetch_related( + Prefetch( + "question_responses", + queryset=FormComponentQuestionAndAnswer.objects.select_related("question"), + ) + ), + ) + ), + ) + ) # Consolidated public endpoints (map-data, assessments-processed, dashboard-data) diff --git a/per/serializers.py b/per/serializers.py index 92200e664..cb2882110 100644 --- a/per/serializers.py +++ b/per/serializers.py @@ -811,6 +811,13 @@ class PerAssessmentSerializer( ): area_responses = AreaResponseSerializer(many=True, required=False) + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + overview_field = self.fields.get("overview") + if overview_field is not None and hasattr(overview_field, "queryset"): + # Avoid N+1 in overview choice labels, since Overview.__str__ touches country. + overview_field.queryset = Overview.objects.select_related("country") + class Meta: model = PerAssessment fields = "__all__"