【发布时间】:2018-05-11 12:55:30
【问题描述】:
我需要一个建议。有时我会遇到在 API 中需要从一些数据库表中检索大量数据的情况。当我尝试获取所有数据时 - 这需要很多时间。所以我用一辆小自行车在单个查询中检索数据。
例子:
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 进行 2 次查询。
【问题讨论】:
-
这个问题不适合 SO。在我看来,这是一个非常糟糕的主意。您正在牺牲代码的可维护性和可读性。保持代码简单。如果你真的需要更好的性能,我建议你使用 Redis 和 django-cacheops 来缓存你的查询。我对这些工具有非常积极的体验。
-
虽然它不包含在您的问题中,但我认为您的问题可能是您的查询缺乏优化,很可能是 N+1 选择问题。当您要访问相关表中的每行数据时,请确保将
.prefetch_related(...)添加到 DRF 视图中的查询集。鉴于您所描述的,这听起来像是我以前见过的一个问题,使用 DRF 序列化程序渲染每一行需要至少一次额外的数据库往返。 -
我同意 '.prefetch_related(...)' 和 '.select_related(...) '对于从相关实例中检索所有字段很有用。但我只收集在这个序列化程序中使用的字段。例如,如果 related_table2 有 15 个数据字段,而我只需要名称 - 我只收集一个字段。
-
对这些字段使用注释将是高效且可读的 IMO
标签: python django django-models django-rest-framework