You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django DRF如何实现Survey/Question/Option嵌套模型的POST批量保存

嵌套数据一次性提交实现方案

不需要为每个模型单独创建接口,只需要重写序列化器的create方法处理嵌套关联逻辑,再调整视图支持POST请求即可,具体实现如下:

1. 重写Survey序列化器的create方法

DRF默认不支持嵌套结构的写入操作,需要手动实现层级创建逻辑,同时加事务保证数据一致性:

from django.db import transaction
from rest_framework import serializers

# 原有OptionSerializer、QuestionSerializer不需要修改
class OptionSerializer(serializers.ModelSerializer):
    class Meta:
        model = Option
        exclude = ('question','id')


class QuestionSerializer(serializers.ModelSerializer):
    options = OptionSerializer(many=True)
    class Meta:
        model = Question
        exclude = ('survey',)


class SurveyDetailSerializer(serializers.ModelSerializer):
    creator = serializers.StringRelatedField(read_only=True)
    questions = QuestionSerializer(many=True)

    class Meta:
        model = Survey
        exclude = ('is_active',)
    
    @transaction.atomic
    def create(self, validated_data):
        # 提取关联的问题数据
        questions_data = validated_data.pop('questions')
        # 先创建问卷主表,creator为只读字段,从请求上下文取当前登录用户
        survey = Survey.objects.create(
            creator=self.context['request'].user,
            **validated_data
        )
        # 遍历创建所有问题
        for question_data in questions_data:
            options_data = question_data.pop('options')
            # 创建问题并关联当前问卷
            question = Question.objects.create(survey=survey, **question_data)
            # 遍历创建当前问题的所有选项
            for option_data in options_data:
                Option.objects.create(question=question, **option_data)
        return survey

2. 调整视图支持POST请求

原有视图仅支持GET查询,调整后同时支持查询和创建:

from rest_framework import generics, mixins

class SurveyView(mixins.RetrieveModelMixin,
                 mixins.CreateModelMixin,
                 generics.GenericAPIView):
    """查询单份问卷、创建完整问卷接口"""
    queryset = Survey.objects.all()
    serializer_class = SurveyDetailSerializer

    # 处理GET查询请求
    def get(self, request, *args, **kwargs):
        return self.retrieve(request, *args, **kwargs)

    # 处理POST创建请求
    def post(self, request, *args, **kwargs):
        return self.create(request, *args, **kwargs)

如果不需要同一路径支持查询,也可以单独使用generics.CreateAPIView实现创建接口。

3. 前端提交格式

和GET返回格式基本一致,只需要剔除只读字段(id、creator、created_at等)即可,提交示例:

{
    "name": "新调查问卷",
    "description": "问卷描述内容",
    "questions": [
        {
            "answer_type": "single option",
            "text": "第一题内容?",
            "options": [
                {"text": "选项A"},
                {"text": "选项B"}
            ]
        }
    ]
}

补充说明

  • 如果后续需要支持嵌套更新(PUT/PATCH),同理重写序列化器的update方法即可,逻辑为:先更新问卷主字段,再对比处理关联的问题、选项的新增/修改/删除操作。
  • 原有字段校验逻辑会自动生效,不需要额外修改。

内容的提问来源于stack exchange,提问作者Alice_nvbr

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.02 19:24:04