Django REST Framework使用Serializer创建User及关联ExtendUser数据
实现方案
要在注册接口同时创建User主表和关联ExtendUser扩展表数据,不需要拆分两个序列化器调用,直接改造UserSerializer嵌套处理扩展字段即可,具体修改步骤如下:
1. 改造serializers.py
在UserSerializer中新增ExtendUser对应的写入字段,调整save方法逻辑,创建主表用户后同步创建关联扩展表记录,改造后代码如下:
class UserSerializer(serializers.ModelSerializer): password2 = serializers.CharField(write_only=True, style={'input_type':'password'}) # 新增扩展表对应字段,标记为只写,仅用于入参校验写入 address = serializers.CharField(write_only=True, max_length=300) phone = serializers.CharField(write_only=True, max_length=16) picture = serializers.ImageField(write_only=True, required=False, default="default.webp") class Meta: model = User # 将扩展字段加入字段列表 fields = ['email', 'first_name', 'password', 'password2', 'address', 'phone', 'picture'] extra_kwargs = {'password' : {'write_only':True,}} def save(self): password = self.validated_data['password'] password2 = self.validated_data['password2'] # 原有密码、邮箱校验逻辑 if len(password) < 8: raise serializers.ValidationError({'error':'密码长度需为8-16位,且包含数字和字母/特殊字符'}) if password != password2: raise serializers.ValidationError({'Password':'两次输入的密码不一致'}) email = self.validated_data['email'] if User.objects.filter(email=email).exists(): raise serializers.ValidationError({'E-mail': f"邮箱{email}已被注册,请更换邮箱"}) # 创建User主表记录 user = User.objects.create_user( username=email, email=email, password=password, first_name=self.validated_data['first_name'] ) # 同步创建关联ExtendUser扩展表记录 ExtendUser.objects.create( user=user, address=self.validated_data['address'], phone=self.validated_data['phone'], picture=self.validated_data.get('picture', "default.webp") ) return user class ExtendUserSerializer(serializers.ModelSerializer): class Meta: model = ExtendUser fields = '__all__'
原有的ExtendUserSerializer可以保留,供其他查询、更新扩展信息的接口使用,注册场景不需要单独调用。
2. 修复views.py的逻辑错误
原代码中生成JWT令牌的逻辑存在bug:RefreshToken.for_user()需要传入User模型实例,而非序列化器实例,需要先接收save()方法返回的已创建用户对象再生成令牌,修改后代码如下:
class UserRegistration(APIView): def post(self, request): serializer = UserSerializer(data=request.data) serializer.is_valid(raise_exception=True) # 接收save返回的已创建用户实例 created_user = serializer.save() # 传入用户实例生成令牌 refreshToken = RefreshToken.for_user(created_user) context = { 'access': str(refreshToken.access_token), 'refresh': str(refreshToken) } return Response(context, status=status.HTTP_201_CREATED)
3. 接口调用说明
注册接口请求时直接将扩展字段和基础用户字段一同传入即可,因为包含图片上传字段,请求需使用multipart/form-data格式,必填参数包括:
- email:注册邮箱
- first_name:用户名称
- password:登录密码
- password2:确认密码
- address:用户地址
- phone:手机号
- picture:用户头像(可选,不传则使用默认头像default.webp)
如果需要接口返回用户信息时同步带出ExtendUser的扩展字段,只需要去掉对应扩展字段的
write_only=True配置,或者嵌套ExtendUserSerializer做读场景的字段映射即可,当前配置已完全满足注册时同时创建两条关联数据的需求。
内容的提问来源于stack exchange,提问作者Partho Debnath
相关产品推荐
相关产品推荐

