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

DRF对象级validate函数失效,抛出TypeError而非预期ValidationError

问题:DRF自定义validate方法校验失败时触发TypeError而非预期ValidationError

在基于Django REST Framework开发接口时,为自定义的IdentitySerializer实现了对象级validate方法,用于校验firstName与lastName不能相同。但发送包含相同firstName和lastName的POST请求时,未抛出预期的ValidationError(提示"first name last name cannot be same"),反而触发TypeError,错误信息如下:

"C:\Python310\lib\site-packages\rest_framework\serializers.py", line 204, in save
    validated_data = {**self.validated_data, **kwargs}
TypeError: 'ValidationError' object is not a mapping

相关代码及请求体如下:

views.py

from rest_framework import generics
from .models import Identity
from .serializers import IdentitySerializer
from rest_framework.response import Response
from rest_framework import status
from rest_framework.decorators import api_view

@api_view(['GET'])
def IdentityListApiView(request):
   queryset = Identity.objects.all()
   serializer = IdentitySerializer(queryset, many=True)
   return Response(serializer.data)

@api_view(['POST']) 
def IdentityDetailApiView(request):
    serializer = IdentitySerializer(data=request.data)
    print("isData valid:", serializer.is_valid())
    if serializer.is_valid(raise_exception=True):
         serializer.save()
    return Response(serializer.data, status=status.HTTP_201_CREATED)

serializers.py

from rest_framework import serializers
from .models import Identity

class IdentitySerializer(serializers.Serializer):
    firstName=serializers.CharField(max_length=40)
    lastName=serializers.CharField(max_length=40)
    age=serializers.IntegerField(max_value=None, min_value=None)
    mobileNo=serializers.IntegerField(read_only=False)
    isMale=serializers.BooleanField(read_only=False)

    def create(self, validated_data):  
      return Identity.objects.create(**validated_data)

    def validate(self, data):
        if data['firstName'] == data['lastName']:
            return serializers.ValidationError('first name last name cannot be same')
        return data

models.py

from django.db import models

class Identity(models.Model):
    firstName = models.CharField(max_length=40, null=False, blank=False, default='M')
    lastName = models.CharField(max_length=40, null=False, blank=False, default='K')
    age = models.IntegerField(null=True)
    mobileNo = models.IntegerField(null=True)
    isMale = models.BooleanField(blank=True, null=True)

请求体

{
    "firstName": "abc",
    "lastName": "abc",
    "age": "56",
    "mobileNo":" 589643145",
    "isMale": true
}

解决方法

错误原因

DRF的validate方法规则:验证通过时返回校验后的data字典;验证失败时必须抛出ValidationError异常,而非返回该异常对象。当前代码错误地将ValidationError对象作为返回值,导致self.validated_data被赋值为异常对象,后续serializer.save()执行时试图将其当作字典解构,因此触发TypeError。

修正后的serializers.py代码

修改validate方法,将return serializers.ValidationError(...)改为raise serializers.ValidationError(...):

from rest_framework import serializers
from .models import Identity

class IdentitySerializer(serializers.Serializer):
    firstName=serializers.CharField(max_length=40)
    lastName=serializers.CharField(max_length=40)
    age=serializers.IntegerField(max_value=None, min_value=None)
    mobileNo=serializers.IntegerField(read_only=False)
    isMale=serializers.BooleanField(read_only=False)

    def create(self, validated_data):  
      return Identity.objects.create(**validated_data)

    def validate(self, data):
        if data['firstName'] == data['lastName']:
            # 改为抛出异常,而非返回
            raise serializers.ValidationError('first name last name cannot be same')
        return data

验证效果

修改后,发送相同POST请求时,DRF会自动捕获ValidationError,返回包含错误信息的400响应,符合预期校验逻辑。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 04:17:01