Django DRF使用PrimaryKeyRelatedField时overfetching问题如何解决
你遇到的过取问题根源是prefetch_related("characters")默认会查询关联Character模型的全部字段,而序列化仅需要id字段,两种优化方案如下:
方案1:最小改动优化(兼容性最好)
自定义Prefetch对象,指定关联查询仅拉取id字段,无需修改序列化器原有逻辑:
# 视图文件新增导入 from django.db.models import Prefetch class QuestController(viewsets.ModelViewSet): serializer_class = QuestSerializer def get_queryset(self): return Quest.objects.filter(campaign_id=self.kwargs["campaign_id"]).prefetch_related( Prefetch("characters", queryset=Character.objects.only("id")) ) def perform_create(self, serializer): return serializer.save(campaign_id=self.kwargs["campaign_id"])
优化后关联查询仅会取Character表的id字段,大幅减少冗余数据拉取量。
方案2:最优性能方案(完全跳过Character表)
直接通过聚合函数从多对多中间表拉取id数组,不需要关联查询Character表,完全符合你预期的SQL逻辑:
# 视图文件新增导入(PostgreSQL环境,其他数据库可替换为对应聚合函数) from django.db.models import ArrayAgg class QuestController(viewsets.ModelViewSet): serializer_class = QuestSerializer def get_queryset(self): return Quest.objects.filter(campaign_id=self.kwargs["campaign_id"]).annotate( character_ids=ArrayAgg("characters__id") ) def perform_create(self, serializer): return serializer.save(campaign_id=self.kwargs["campaign_id"])
同步修改序列化器,直接读取聚合好的id数组:
class QuestSerializer(serializers.ModelSerializer): characters = serializers.ListField( child=serializers.IntegerField(), source="character_ids", read_only=True ) class Meta: model = Quest fields = "__all__"
如果使用MySQL等不支持ArrayAgg的数据库,可选用第一种方案,兼容性更强。
内容的提问来源于stack exchange,提问作者Kevin Renskers
相关产品推荐
相关产品推荐

