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

Django Serializer自定义邮箱校验信息不生效原因咨询

问题

我编写了如下的RegisterSerializer代码:

class RegisterSerializer(ModelSerializer):
    username = CharField(required=True)

    class Meta:
        model = User
        fields = ['username', 'password', 'email']

    def create(self, validated_data):
        if User.objects.filter(username=validated_data['username']).exists():
            raise ValidationError('ushbu username mavjud!')
        if User.objects.filter(email=validated_data['email']).exists():
            raise ValidationError("ushbu email mavjud!")
        user = User.objects.create_user(
            username=validated_data['username'],
            password=validated_data['password'],
            email=validated_data['email']
        )
        return user

其中用户名的校验逻辑可以正常返回自定义错误信息,但邮箱的校验逻辑不生效,反而返回DRF默认提示:

"email": [
    "user with this email already exists."
  ]

我期望使用序列化器内定义的校验错误信息,请问这是为什么?

原因

DRF的ModelSerializer会自动为模型中带有unique=True约束的字段生成UniqueValidator,这个校验器会在序列化器的validate阶段(也就是create方法执行之前)触发。

你的代码中:

  • 显式声明了username字段为CharField,但没有添加UniqueValidator,因此序列化器层面不会自动校验用户名唯一性,所以create方法里的自定义校验逻辑会执行。
  • 没有显式声明email字段,序列化器会根据User模型中email字段的unique=True约束自动添加UniqueValidator,并使用默认错误信息。这个内置校验会在create方法执行前就触发,导致你写的邮箱校验代码根本没机会运行。

解决方案

有两种常用的解决方式:

方式一:显式声明email字段,自定义UniqueValidator的错误信息

from rest_framework.validators import UniqueValidator

class RegisterSerializer(ModelSerializer):
    username = CharField(required=True)
    email = CharField(
        required=True,
        validators=[UniqueValidator(queryset=User.objects.all(), message="ushbu email mavjud!")]
    )

    class Meta:
        model = User
        fields = ['username', 'password', 'email']

    def create(self, validated_data):
        # 此时用户名和邮箱的唯一性已由序列化器校验完成,可移除create内的重复校验
        user = User.objects.create_user(
            username=validated_data['username'],
            password=validated_data['password'],
            email=validated_data['email']
        )
        return user

方式二:在序列化器的validate方法中统一处理校验

如果需要更自定义的校验逻辑,可以重写validate方法,同时注意要禁用自动生成的UniqueValidator:

class RegisterSerializer(ModelSerializer):
    username = CharField(required=True)
    # 显式声明email字段,不添加默认的UniqueValidator
    email = CharField(required=True)

    class Meta:
        model = User
        fields = ['username', 'password', 'email']
        # 禁用自动生成的validators
        extra_kwargs = {
            'email': {'validators': []},
            'username': {'validators': []}
        }

    def validate(self, data):
        if User.objects.filter(username=data['username']).exists():
            raise ValidationError({'username': 'ushbu username mavjud!'})
        if User.objects.filter(email=data['email']).exists():
            raise ValidationError({'email': 'ushbu email mavjud!'})
        return data

    def create(self, validated_data):
        user = User.objects.create_user(
            username=validated_data['username'],
            password=validated_data['password'],
            email=validated_data['email']
        )
        return user

注意:方式二中需要通过extra_kwargs禁用自动生成的validators,否则内置校验还是会先触发。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 10:44:54