如何优化查询 django rest-framework

Posted

技术标签:

【中文标题】如何优化查询 django rest-framework【英文标题】:How can I optimize queries django rest-framework 【发布时间】:2018-11-29 16:40:32 【问题描述】:

我有以下序列化程序

    class AutoSerializer(serializers.ModelSerializer):
        class Meta:
            model = Auto
            fields = ("nombre",)


    class MarcaSerializer(WritableNestedModelSerializer):
        autos = AutoSerializer(many=True)

        class Meta:
            model = Marca
            fields = ("codigo", "descripcion", "autos")

模型视图集

    class MarcaViewSet(viewsets.ModelViewSet):
        queryset = Marca.objects.all()
        serializer_class = MarcaSerializer

        def list(self, request, *args, **kwargs):
            queryset = self.queryset
            serializer = self.get_serializer(queryset, many=True)
            return Response(serializer.data)

Querys

如何优化对基地的访问,即减少查询次数

【问题讨论】:

【参考方案1】:

通过使用.prefetch_related(..) 一次获取相关的Auto 实例:

class MarcaViewSet(viewsets.ModelViewSet):
        queryset = Marca.objects.prefetch_related('autos').all()
        serializer_class = MarcaSerializer

        def list(self, request, *args, **kwargs):
            queryset = self.queryset
            serializer = self.get_serializer(queryset, many=True)
            return Response(serializer.data)

这将首先获取Marca 对象,然后使用JOIN 查找所有相关的Auto 对象,并通过单个 获取所有这些对象到内存中也是。

因此Auto 对象被批量 加载,而不是每次为特定 Marca 对象获取Autos 时都懒惰地加载。

这种优化记录在@Jerin Peter George 提到的文章中:"Optimizing slow Django REST Framework performance"。

本文还讨论了如何在 serializer 一侧指定此类预取,以便在完成其他任务的情况下,预取完成。所以我们可以例如写:

class AutoSerializer(serializers.ModelSerializer):

    class Meta:
        model = Auto
        fields = ("nombre",)


class MarcaSerializer(WritableNestedModelSerializer):
    autos = AutoSerializer(many=True)

    @classmethod
    def setup_eager_loading(cls, queryset):
        return queryset.prefetch_related('autos')

    class Meta:
        model = Marca
        fields = ("codigo", "descripcion", "autos")

然后写:

class MarcaViewSet(viewsets.ModelViewSet):
    queryset = Marca.objects.all()
    serializer_class = MarcaSerializer

    def list(self, request, *args, **kwargs):
        serializer = self.get_serializer
        queryset = serializer.setup_eager_loading(self.queryset)
        serializer = serializer(queryset, many=True)
        return Response(serializer.data)

【讨论】:

我读过的关于Django Query Optimization的最好的文章之一 @JerinPeterGeorge:谢谢。我在答案中添加了文章的链接。

以上是关于如何优化查询 django rest-framework的主要内容,如果未能解决你的问题,请参考以下文章

在 Django Admin 中使用 raw_id_fields 时如何优化查询数量

如何优化 django oracle 连接?

如何找到触发查询的位置 [Django]

如何优化这个复杂的查询?

优化 django 数据库查询

Django进阶之查询优化extra注入SQL及批量创建