Python 如何在Django Rest框架中优化序列化模型数据?

Python 如何在Django Rest框架中优化序列化模型数据?,python,django,django-models,django-rest-framework,Python,Django,Django Models,Django Rest Framework,我需要一个建议。有时,在API中,我需要从一些db表中检索大量数据。当我试图获取所有数据时,这需要很多时间。因此,我使用一个小自行车在单个查询中检索数据 例如: class SomeModelSerializer(serializers.ModelSerializer): related_name1 = serializers.SerializerMethodField() related_name2 = serializers.SerializerMethodField()

我需要一个建议。有时,在API中,我需要从一些db表中检索大量数据。当我试图获取所有数据时,这需要很多时间。因此,我使用一个小自行车在单个查询中检索数据

例如:

class SomeModelSerializer(serializers.ModelSerializer):
    related_name1 = serializers.SerializerMethodField()
    related_name2 = serializers.SerializerMethodField()
    related_name3 = serializers.SerializerMethodField()

    def get_related_name1(self, obj):
        return self.values[obj.id].get('related_table1__name')

    def get_related_name2(self, obj):
        return self.values[obj.id].get('related_table1__related_table2__name')

    def get_related_name3(self, obj):
        return self.values[obj.id].get('related_table3__name')

    def __init__(self, *args, **kwargs):
        super(SomeModelSerializer, self).__init__(*args, **kwargs)
        # Collect all necessary data from BD.
        self.values = {}
        if self.instance:
            for some_model_values in self.instance.values(
                'id',
                'related_table1__name',
                'related_table1__related_table2__name',
                'related_table3__name'
            ).iterator():
                self.values[some_model_values['id']] = some_model_values

    class Meta:
        model = SomeModel
        fields = ('id', 'related_name1', 'related_name2', 'related_name3')
它适用于需要检索大量数据的情况,但它比简单的序列化程序花费更多的编码时间。 这是优化数据检索的好主意,还是有其他解决方案


此解决方案针对任何查询集向DB进行两次查询。

我们可以简单地在序列化程序中将方法
重写为\u表示

class SomeModelSerializer(serializers.ModelSerializer):

  def to_representation(self, instance):
    data = super(SomeModelSerializer, self).to_representation(instance)
    data.update({
       'related_name1': instance.related_table1.name,
       'related_name2': instance.related_table2.name
       # more fields & values
    })
    return data

  class Meta:
    model = SomeModel
    fields = ('id',)
我想,写它并不是那么简单
相关信息:

您是否尝试在使用
SomeModelSerializer
视图中使用
预取相关的
?差不多

from rest_framework import viewsets

from myapp.models import SomeModel
from myapp.api.v1.serializers import SomeModelSerializer


class SomeModelViewSet(viewsets.ModelViewSet):
    serializer_class = SomeModelSerializer
    queryset = SomeModel.objects.prefetch_related(
        'related_table1',
        'related_table1__related_table2',
        'related_table3',
    )

这个问题属于这个问题,不适合这么说。在我看来,这是一个非常糟糕的主意。您正在牺牲代码的可维护性和可读性。保持代码简单。如果您确实需要更好的性能,我建议您使用Redis并缓存查询。我对这些工具有着非常积极的经验。虽然您的问题中没有包括这些工具,但我认为您的问题可能是您的查询缺乏优化,很可能是N+1选择问题。当您要访问每行相关表中的数据时,请确保在DRF视图中的查询集中添加一个
.prefetch\u related(…)
。根据您的描述,这听起来像是我以前见过的问题,使用DRF序列化程序呈现每一行至少需要一次到数据库的额外往返。我同意“.prefetch_related(…)”和“.select_related(…)”对于从相关实例检索所有字段非常有用。但我只收集在此序列化程序中使用的字段。例如,如果related_table2有15个包含数据的字段,而我只需要名称-我只收集一个字段。您编写了标准序列化程序解决方案,但它会进行大量查询以收集所有数据。我尝试优化收集。您的解决方案为每个相关表向DB查询,同时我的解决方案为每个查询集向DB查询2次。我尝试减少对数据库的查询。我们可以在查询集上使用预回迁相关或选择相关。如果我正确理解“.select\u related(…)”的工作,它将从相关实例检索所有字段。如果表2有15个字段包含数据,它将收集所有这些字段。在我的代码中-我只收集此序列化程序所需的字段。是的,我使用select_related和prefetch_related对解决方案进行了测试,它对小queryset很有效,但对于具有数千个条目和5-10个相关表的queryset进行收集-它花费了太多的时间(在本例中收集了大量无用的数据)。
from rest_framework import viewsets

from myapp.models import SomeModel
from myapp.api.v1.serializers import SomeModelSerializer


class SomeModelViewSet(viewsets.ModelViewSet):
    serializer_class = SomeModelSerializer
    queryset = SomeModel.objects.prefetch_related(
        'related_table1',
        'related_table1__related_table2',
        'related_table3',
    )