I have a situation where my model has a foreign key relationship:
and my serializer:
class ParentSerializer(serializer.ModelSerializer): child = serializers.SerializerMethodField('get_children_ordered') def get_children_ordered(self, parent): queryset = Child.objects.filter(parent=parent).select_related('parent') serialized_data = ChildSerializer(queryset, many=True, read_only=True, context=self.context) return serialized_data.data class Meta: model = Parent
When I call Parent in my views for N number of parents, Django makes N database call numbers inside the serializer when it captures children. Is there a way to get ALL children for ALL parents to minimize the number of calls in the database?
I tried this, but it does not seem to solve my problem:
class ParentList(generics.ListAPIView): def get_queryset(self): queryset = Parent.objects.prefetch_related('child') return queryset serializer_class = ParentSerializer permission_classes = (permissions.IsAuthenticated,)
EDIT
I updated the code below to reflect the feedback from Alex .... which solves N + 1 for one nested relationship.
# serializer.py class ParentSerializer(serializer.ModelSerializer): child = serializers.SerializerMethodField('get_children_ordered') def get_children_ordered(self, parent):
Now let's say I have another model that is a grandson:
If I put the following in my views.py for the queryset parent:
queryset = Parent.objects.prefetch_related(children, 'children__grandchildren')
It doesn't seem like these grandchildren are being ported to ChildSerializer, and so again I am running another N + 1 issue. Any thoughts on this?
EDIT 2
Perhaps this will provide clarity ... Maybe the reason I still encounter calls to the N + 1 database is because my children and grandchild classes are Polymorphic .... ie
and my serializers look like this:
# serializer.py class ChildSerializer(serializer.ModelSerializer): grandchild = serializers.SerializerMethodField('get_children_ordered') def to_representation(self, value): if isinstance(value, Son): return SonSerializer(value, context=self.context).to_representation(value) if isinstance(value, Daughter): return DaughterSerializer(value, context=self.context).to_representation(value) class Meta: model = Child class ParentSerializer(serializer.ModelSerializer): child = serializers.SerializerMethodField('get_children_ordered') def get_children_ordered(self, parent): queryset = Child.objects.filter(parent=parent).select_related('parent') serialized_data = ChildSerializer(queryset, many=True, read_only=True, context=self.context) return serialized_data.data class Meta: model = Parent
Plus for Granddaughter, grandson, I will spare you the details of the code, but I think you will get the picture.
When I run my view for ParentList and control the database queries, I get something in accordance with thousands of queries, only for a few parents.
If I run the same code in the django shell, I can execute the same request from no more than 25 requests. I suspect, maybe this is due to the fact that I'm using the django-polymorphic library? The reason is that there is a table of the Child and GrandChild database, in addition to each table "Son / Daughter", "Grandson / Granddaughter", a total of 6 tables. through these objects. So my gut tells me that I'm missing these polymorphic tables.
Or maybe there is a more elegant solution for my daata model?