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

DRF自定义User模型序列化创建用户时save操作报错问题咨询

问题诊断

你的序列化逻辑存在多处明显错误,是触发异常的核心原因:

  • 基础序列化器类型选择错误:UserResponseSerializer和UserRegistrationRequsetSerializer都继承了普通serializers.Serializer,该类的默认create方法只会返回校验后的字典数据,不会生成你的User模型实例,调用user.set_password()时自然会抛出属性不存在异常。
  • 嵌套参数结构没有正确解析:UserRegistrationRequsetSerializer校验后的数据结构为{"user": {用户字段}, "password": "xxx"},你直接将完整结构传给父类create方法,无法正确提取用户字段用于模型创建。
  • 字段类型不匹配:模型中contact字段为PhoneNumberField(本质是字符串类型,存储带国际区号的手机号格式),但序列化器中定义为IntegerField,参数校验或存储时会触发类型错误。
  • 异常处理逻辑不合理:视图层捕获所有异常直接返回404状态码,完全掩盖了真实错误信息,无法定位问题。
修复方案

1. 重写序列化器(serializers.py)

from rest_framework import serializers
from .models import User

# 通用用户信息序列化器,继承ModelSerializer自动绑定模型逻辑
class UserSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = ["id", "first_name", "last_name", "email", "username", "profile_image", "status", "contact", "is_staff", "is_active"]
        read_only_fields = ["id", "is_staff", "is_active"]

# 用户注册请求序列化器
class UserRegistrationRequestSerializer(serializers.Serializer):
    user = UserSerializer(required=True)
    password = serializers.CharField(required=True, max_length=255, allow_blank=False, write_only=True)

    def create(self, validated_data):
        # 提取用户字段和密码
        user_data = validated_data.pop("user")
        password = validated_data.pop("password")
        # 创建用户实例
        user = User.objects.create(**user_data)
        # 加密存储密码
        user.set_password(password)
        user.save()
        return user

2. 优化视图逻辑(views.py)

from rest_framework import viewsets
from rest_framework.response import Response
from rest_framework import status
from django.shortcuts import get_object_or_404
from .models import User
from .serializers import UserSerializer, UserRegistrationRequestSerializer
from drf_yasg.utils import swagger_auto_schema

class UserViewSet(viewsets.ViewSet):
    def list(self, request):
        queryset = User.objects.all()
        serializer = UserSerializer(queryset, many=True)
        return Response(serializer.data)

    @swagger_auto_schema(request_body=UserRegistrationRequestSerializer)
    def create(self, request, *args, **kwargs):
        serializer = UserRegistrationRequestSerializer(data=request.data)
        # 校验不通过直接返回400错误和错误详情
        serializer.is_valid(raise_exception=True)
        user = serializer.save()
        # 返回创建成功的用户信息
        return Response(UserSerializer(user).data, status=status.HTTP_201_CREATED)

    def retrieve(self, request, pk=None):
        queryset = User.objects.all()
        user = get_object_or_404(queryset, pk=pk)
        serializer = UserSerializer(user)
        return Response(serializer.data)

    # 其余方法按需实现即可

3. 额外注意事项

  • 传入contact参数时需要符合PhoneNumberField的格式要求,通常为带国际区号的字符串,比如"+861234567890",不要传入纯数字格式。
  • 如果你不需要嵌套的user参数结构,也可以直接把所有用户字段和password平放在请求体中,进一步简化序列化器逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.05 12:39:03