Python 如何在Django Rest框架中优化序列化模型数据?
我需要一个建议。有时,在API中,我需要从一些db表中检索大量数据。当我试图获取所有数据时,这需要很多时间。因此,我使用一个小自行车在单个查询中检索数据 例如: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()
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',
)