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
相关产品推荐
相关产品推荐

