DRF中关联User与UserProfile序列化时遇AttributeError问题求助
问题原因
报错AttributeError: 'User' instance has no attribute 'user'的本质是:你试图用操作User模型的视图来处理包含嵌套UserSerializer的UserProfileSerializer,而User实例本身并没有名为user的属性——这个属性属于UserProfile模型,用于关联User。同时,嵌套序列化器默认不支持自动创建关联对象,需要手动处理创建逻辑。
修复方案
1. 完善UserSerializer的密码处理
Django的用户密码需要通过set_password方法加密,不能直接存入数据库,所以重写UserSerializer的create方法:
class UserSerializer(serializers.ModelSerializer): # 保留原字段定义 first_name = serializers.CharField(required=True) last_name = serializers.CharField(required=True) registration_data = serializers.DateTimeField( read_only=True, default=serializers.CreateOnlyDefault(datetime.now()) ) password = serializers.CharField( required=True, write_only=True, max_length=128, error_messages={ 'required': 'Please enter a password.', 'max_length': 'Password should be no more than 128 characters.' }, validators=[ validators.MinLengthValidator(8, message='Password must be at least 8 characters.'), validators.RegexValidator( regex=r'[A-Z]', message='Password must contain at least one uppercase letter.', code='invalid_password' ), validators.RegexValidator( regex=r'[a-z]', message='Password must contain at least one lowercase letter.', code='invalid_password' ), validators.RegexValidator( regex=r'[0-9]', message='Password must contain at least one number.', code='invalid_password' ), validators.RegexValidator( regex=r'[!@#$%^&*()]', message='Password must contain at least one special character.', code='invalid_password' ) ] ) class Meta: model = User exclude = ['id'] def create(self, validated_data): # 提取密码并加密 password = validated_data.pop('password') user = User(**validated_data) user.set_password(password) user.save() return user
2. 重写UserProfileSerializer的创建逻辑
嵌套序列化器不会自动创建关联的User实例,需要手动拆分数据并创建两个模型实例:
class UserProfileSerializer(serializers.ModelSerializer): user = UserSerializer(required=True) class Meta: model = UserProfile fields = ('user', 'phone', 'phone_verified', 'email_verified', 'phone_code', 'email_code') def create(self, validated_data): # 分离嵌套的用户数据 user_data = validated_data.pop('user') # 创建User实例 user = UserSerializer.create(UserSerializer(), validated_data=user_data) # 创建关联的UserProfile实例 profile = UserProfile.objects.create(user=user, **validated_data) return profile
3. 调整视图配置
将视图的序列化器改为UserProfileSerializer,确保操作对象匹配:
class RegisterUserView(generics.CreateAPIView): queryset = UserProfile.objects.all() serializer_class = UserProfileSerializer
4. 正确的请求格式示例
注册时需要传递嵌套的用户信息,JSON格式如下:
{ "user": { "username": "demo_user", "first_name": "Demo", "last_name": "User", "email": "demo@example.com", "password": "DemoPass123!" }, "phone": "13800138000", "phone_code": "123456", "email_code": "654321" }
额外优化建议
- 给
UserProfile的user字段添加related_name:user = models.OneToOneField(User, on_delete=models.CASCADE, related_name='profile'),这样可以通过user.profile快速访问用户的扩展信息。 phone_verified和email_verified已经设置默认值,可以从请求字段中移除,序列化器会自动使用默认值。
内容的提问来源于stack exchange,提问作者Abhishek Surela
相关产品推荐
相关产品推荐

