O Django REST Serializer que executa o banco de dados N + 1 exige vários relacionamentos aninhados, 3 níveis

Eu tenho uma situação em que meu modelo tem um relacionamento de chave estrangeira:

# models.py
class Child(models.Model):
    parent = models.ForeignKey(Parent,)

class Parent(models.Model):
    pass

e meu serializador:

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

Quando eu chamo Parent em meus modos de exibição para N número de Pais, o Django faz N número de chamadas de banco de dados dentro do serializador quando ele pega os filhos. Existe alguma maneira de obter TODOS os filhos de TODOS os Pais para minimizar o número de chamadas ao banco de dados?

Eu tentei isso, mas ele não parece resolver o meu problema:

class ParentList(generics.ListAPIView):

    def get_queryset(self):
        queryset = Parent.objects.prefetch_related('child')
        return queryset

    serializer_class = ParentSerializer
    permission_classes = (permissions.IsAuthenticated,)

EDITAR

Atualizei o código abaixo para refletir o feedback de Alex .... que resolve o N + 1 para um relacionamento aninhado.

# serializer.py
class ParentSerializer(serializer.ModelSerializer):
    child = serializers.SerializerMethodField('get_children_ordered')

    def get_children_ordered(self, parent):
        # The all() call should hit the cache
        serialized_data = ChildSerializer(parent.child.all(), many=True, read_only=True, context=self.context)
        return serialized_data.data

    class Meta:
            model = Parent

# views.py
class ParentList(generics.ListAPIView):

    def get_queryset(self):
        children = Prefetch('child', queryset=Child.objects.select_related('parent'))
        queryset = Parent.objects.prefetch_related(children)
        return queryset

    serializer_class = ParentSerializer
    permission_classes = (permissions.IsAuthenticated,)

Agora, digamos que eu tenho mais um modelo, que é um neto:

# models.py
class GrandChild(models.Model):
    parent = models.ForeignKey(Child,)

class Child(models.Model):
    parent = models.ForeignKey(Parent,)

class Parent(models.Model):
    pass

Se eu colocar o seguinte no meuviews.py para o paiqueryset:

queryset = Parent.objects.prefetch_related(children, 'children__grandchildren')

Não parece que esses netos estão sendo levados para o ChildSerializer e, portanto, novamente estou executando outro problema de N + 1. Alguma idéia sobre este?

EDIT 2

Talvez isso forneça clareza ... Talvez o motivo pelo qual ainda estou executando chamadas de banco de dados N + 1 seja porque minhas classes de filhos e netos são polimórficas ...

# models.py
class GrandChild(PolymorphicModel):
    child = models.ForeignKey(Child,)

class GrandSon(GrandChild):
    pass

class GrandDaughter(GrandChild):
    pass

class Child(PolymorphicModel):
    parent = models.ForeignKey(Parent,)

class Son(Child):
    pass

class Daughter(Child):
    pass

class Parent(models.Model):
    pass

e meus serializadores ficam mais ou menos assim:

# 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

Mais o mesmo para Grandaughter, neto, pouparei os detalhes em código, mas acho que você entendeu.

Quando executo minha visão para ParentList e monitorei consultas de banco de dados, obtive algo como milhares de consultas, apenas para alguns pais.

Se eu executar o mesmo código no shell do django, eu posso realizar a mesma consulta com no máximo 25 consultas. Eu suspeito que talvez tenha algo a ver com o fato de eu estar usando a biblioteca django-polimórfica. O motivo é que, há uma tabela de banco de dados Child e GrandChild, em acréscimos a cada tabela Filho / Filha, Neto / Neta, para um total de 6 tabelas. através desses objetos. Então meu intestino me diz que estou sentindo falta daquelas tabelas polimórficas.

Ou talvez haja uma solução mais elegante para o meu modelo de dados?

questionAnswers(2)

yourAnswerToTheQuestion