不使用原生SQL实现DRF嵌套序列化:获取指定用户关联问卷及嵌套答案
实现方案
第一步:优化ORM查询
优先使用Django自带的关联查询+预取机制,避免N+1查询问题,同时过滤出仅包含目标用户答案的问卷,只拉取需要的字段降低开销:
from django.db.models import Prefetch target_user_id = "你要查询的用户ID" polls = Poll.objects.filter( pollanswer__user_id=target_user_id ).distinct().prefetch_related( Prefetch( # 如果你给ForeignKey设置了related_name,这里替换为自定义的related_name "pollanswer_set", # 仅预取目标用户的答案 queryset=PollAnswer.objects.filter(user_id=target_user_id).only("id", "text"), to_attr="user_answers" ) )
第二步:编写对应序列化器
直接基于Poll模型编写序列化器,用SerializerMethodField自定义answers字段的返回格式:
from rest_framework import serializers class PollWithUserAnswerSerializer(serializers.ModelSerializer): # 映射id字段为返回要求的poll_id poll_id = serializers.IntegerField(source="id") answers = serializers.SerializerMethodField() class Meta: model = Poll fields = ["poll_id", "answers"] def get_answers(self, obj): answer_dict = {} # 直接读取预取好的答案,不会触发额外查询 for index, answer in enumerate(obj.user_answers): # 按你要求的格式拼接key,也可以替换为answer.id作为序号 key = f"{target_user_id}_answer{index+1}" answer_dict[key] = answer.text return answer_dict
第三步:视图调用示例
from rest_framework.views import APIView from rest_framework.response import Response class UserPollAnswerView(APIView): def get(self, request): target_user_id = request.query_params.get("user_id") if not target_user_id: return Response({"error": "缺少user_id参数"}, status=400) # 执行查询逻辑 polls = Poll.objects.filter( pollanswer__user_id=target_user_id ).distinct().prefetch_related( Prefetch( "pollanswer_set", queryset=PollAnswer.objects.filter(user_id=target_user_id).only("id", "text"), to_attr="user_answers" ) ) serializer = PollWithUserAnswerSerializer(polls, many=True) return Response(serializer.data)
Django ORM学习指南推荐
- 优先通读Django官方文档的ORM模块,覆盖基础查询、关联查询、性能优化、查询表达式等核心内容,是最权威的学习资料
- DRF序列化器相关内容直接学习DRF官方文档的序列化器章节,重点掌握嵌套序列化、自定义字段、方法字段的使用规则
- 日常多做关联模型的查询、序列化实战练习,遇到问题优先排查字段定义、查询逻辑的参数配置
内容的提问来源于stack exchange,提问作者swats-the-floran
相关产品推荐
相关产品推荐

