Django REST Framework POST请求create()参数数量不匹配报错如何解决
问题原因与修复方案
报错直接诱因
你定义序列化器create方法时参数配置错误:DRF调用序列化器的create方法时,会将验证后的数据字典作为位置参数传入,你写的def create(self, **validated_data): 只能接收关键字参数,位置参数传入时就会触发「参数数量不匹配」的报错。
其余代码错误整理
序列化器部分
- 两个序列化器都继承了
serializers.Serializer,但配置了Model相关的Meta类,普通Serializer不会读取Meta配置,应该改为继承serializers.ModelSerializer is_existing_student字段定义多了一个等于号,存在语法错误- 创建Student实例时外键字段名写错,需要和你Student模型中定义的外键字段名匹配
视图部分
- 自定义action中没有初始化serializer变量,直接调用
serializer.is_valid()属于未定义变量错误 - 错误调用
School.create()方法,模型实例创建应该用School.objects.create(),或者直接调用序列化器的save()方法 - 逻辑混乱:
detail=True的action是针对已存在的学校实例操作,你却在里面执行创建学校的逻辑 - 验证失败返回204状态码不符合HTTP规范,应该返回400带错误信息
修复后代码
serializers.py
# 改为继承ModelSerializer才能自动读取Meta配置 class StudentSerializer(serializers.ModelSerializer): class Meta: model = Student fields = ['first_name'] class SchoolSerializer(serializers.ModelSerializer): # 去掉多余的等于号修正语法错误 is_existing_student = serializers.BooleanField() student = StudentSerializer(many=True) class Meta: model = School fields = ['is_existing_student', 'name', 'city', 'street', 'student'] # 修正create方法参数,接收位置参数validated_data def create(self, validated_data): student_data = validated_data.pop('student') school_instance = School.objects.create(**validated_data) for s_data in student_data: # 外键字段名请替换为你Student模型中实际指向School的字段名 Student.objects.create(school=school_instance, **s_data) return school_instance
views.py
如果不需要特殊逻辑,直接用CreateModelMixin提供的默认创建接口即可,POST请求直接发往/register/就能正常使用,无需编写自定义action。如果需要保留自定义action,参考以下写法:
from rest_framework import status from rest_framework.response import Response class SchoolViewSet(mixins.CreateModelMixin, RetrieveModelMixin, ListModelMixin, GenericViewSet): serializer_class = SchoolSerializer queryset = School.objects.all() # 创建新资源不需要对应已有实例,detail设为False @action(detail=False, methods=['POST']) def school(self, request, *args, **kwargs): # 用请求数据初始化序列化器 serializer = self.get_serializer(data=request.data) serializer.is_valid(raise_exception=True) # 调用序列化器save方法自动执行你编写的create逻辑 school_instance = serializer.save() return Response(self.get_serializer(school_instance).data, status=status.HTTP_201_CREATED)
路由配置
无需修改,保持原有配置即可:
router.register(r'register', SchoolViewSet)
验证请求示例
POST请求体格式参考:
{ "is_existing_student": false, "name": "第一中学", "city": "北京", "street": "XX路100号", "student": [ {"first_name": "张三"}, {"first_name": "李四"} ] }
默认创建接口请求地址为/register/,自定义action接口请求地址为/register/school/。
内容的提问来源于stack exchange,提问作者user13066942
相关产品推荐
相关产品推荐

