如何在 django(DRF)中检索对象列表(包括 ForeignKey 字段数据)而不显着增加数据库调用时间

Posted

技术标签:

【中文标题】如何在 django(DRF)中检索对象列表(包括 ForeignKey 字段数据)而不显着增加数据库调用时间【英文标题】:How to retrieve a list of objects (including ForeignKey Field data) in django (DRF) without significantly increasing DB call times 【发布时间】:2021-09-17 15:00:32 【问题描述】:

我在一个 django DRF 项目中有三个模型:

class ModelA(models.Model):
    name = ....
    other fields...

class ModelB(models.Model):
    name = ....
    other fields...

class ModelC(models.Model):
    name = ....
    model_a = FKField(ModelA)
    model_b = FKField(ModelB)

我为每个模型使用默认的 ModelViewSet 序列化程序。

在我的 react 前端,我正在显示一个包含 100 个 ModelC 对象的表格。请求耗时 300 毫秒。问题是,我不想在我的表中只显示 modelA 和 ModelB 的 pk id,而是想显示它们的名称。当我使用视图集的 list() 方法(检索所有 modelc 对象)时,我尝试了以下方法来获取该数据,但它显着增加了调用时间:

    序列化 ModelCSerializer 中的字段
class ModelCSerializer(serializers.ModelSerializer):
    model_a = ModelASerializer(read_only=True)
    model_b = ModelBSerializer(read_only=True)
    class Meta:
        model = ModelC
        fields = '__all__'
    创建新的序列化程序以仅返回 FK 对象的名称
class ModelCSerializer(serializers.ModelSerializer):
    model_a = ModelANameSerializer(read_only=True) (serializer only returns id and name)
    model_b = ModelBNameSerializer(read_only=True) (serializer only returns id and name)
    class Meta:
        model = ModelC
        fields = '__all__'
    字符串相关字段
class ModelCSerializer(serializers.ModelSerializer):
    model_a = serializer.StringRelatedField()
    model_b = serializer.StringRelatedField()
    class Meta:
        model = ModelC
        fields = '__all__'

每种方式都返回我需要的数据(除了数字 3 需要更多工作来获取 FKobject 的 id),但现在我的表请求需要 5.5 秒。有没有办法在不显着增加通话时间的情况下做到这一点?我猜这是因为数据库为我检索的每个对象查找 3 个对象。

此外,我无法将 ModelA 和 ModelB 的 primary_key 设为名称字段,因为它们不是唯一的。

谢谢

感谢下面的 bdbd,为我的示例编辑答案:

class ModelCViewSet(viewsets.ModelViewSet):
    queryset = ModelC.objects.select_related('model_a', 'model_b').all()
    # ...

【问题讨论】:

查看select_related 以优化您的查询:https://docs.djangoproject.com/en/3.2/ref/models/querysets/#select-related 可以分享您的查询集或您如何使用序列化程序? 我在 ModelCViewSet 中的查询集只是 ModelC.objects.all()。我会试试 select_related 让你知道,听起来很有希望 【参考方案1】:

您可以为此使用select_related 来优化您的查询,并确保您的ModelC 中的每个对象都不会造成额外的数据库命中

【讨论】:

以上是关于如何在 django(DRF)中检索对象列表(包括 ForeignKey 字段数据)而不显着增加数据库调用时间的主要内容,如果未能解决你的问题,请参考以下文章

在 DRF 中确定 IsAuthenticated 使用 DRF-JWT 检索使用 Postman 测试的列表

Django - DRF 删除/检索/补丁返回 404 详细信息:“未找到”

Django DRF - 视图集中的补丁请求对象?

Django DRF序列化器或视图中的多表过滤

Django REST Framework:在列表响应中呈现表单元素

在 DRF 中获取序列化程序列表时出现 TypeError