from rest_framework import serializers from .models import CustomUser # 导入你的 CustomUser 模型 from django.contrib.auth.password_validation import validate_password # Django 自带密码验证 # from django.core.exceptions import ValidationError # 如果需要在 validate 方法中手动抛出 class UserRegistrationSerializer(serializers.ModelSerializer): password = serializers.CharField( write_only=True, required=True, validators=[validate_password], style={'input_type': 'password'} # 在DRF的可浏览API中显示为密码输入框 ) password2 = serializers.CharField( write_only=True, required=True, label="确认密码", # 在DRF的可浏览API中的标签 style={'input_type': 'password'} ) # 如果avatar是注册时可选上传的,确保在Meta中处理 avatar = serializers.ImageField(required=False, allow_null=True, max_length=None, use_url=True) class Meta: model = CustomUser # 列出注册时需要用户提供的字段 # 确保这些字段与 CustomUser 模型中定义的一致,特别是 USERNAME_FIELD 和 REQUIRED_FIELDS fields = ('email', 'phone_number', 'nickname', 'password', 'password2', 'school', 'bio', 'avatar') extra_kwargs = { # password 和 password2 已经在上面定义了 write_only=True 'nickname': {'required': True}, # 根据你的 CustomUser.REQUIRED_FIELDS,nickname是必填 'school': {'required': False, 'allow_blank': True}, 'bio': {'required': False, 'allow_blank': True}, # 'avatar': {'required': False} # 已经在上面字段定义中处理 } def validate(self, attrs): if attrs['password'] != attrs['password2']: raise serializers.ValidationError({"password2": "两次输入的密码不匹配。"}) # 将错误关联到password2字段 return attrs def create(self, validated_data): validated_data.pop('password2') # 移除 password2,它不需要保存到模型 # 使用 CustomUser 模型的 create_user 方法创建用户 # 它会处理密码哈希 # validated_data 现在包含了 'email', 'phone_number', 'password', 'nickname' 以及可选的 'school', 'bio', 'avatar' user = CustomUser.objects.create_user(**validated_data) return user class UserProfileSerializer(serializers.ModelSerializer): """ 用于获取和更新用户个人资料的序列化器。 """ avatar_url = serializers.SerializerMethodField() # 用于获取完整的头像URL class Meta: model = CustomUser # 列出用户可以查看和修改的字段 # 不应包含敏感信息如 password (除非是 write_only 用于修改密码的特殊场景) fields = ( 'id', 'email', 'phone_number', 'nickname', 'avatar', 'avatar_url', 'bio', 'school', 'date_joined', 'last_login', 'is_active' # is_active 可以考虑是否允许用户自己修改 ) # 定义只读字段 (在更新时不能被修改,或者需要特殊流程) read_only_fields = ('id', 'email', 'phone_number', 'date_joined', 'last_login', 'avatar_url') # avatar 字段本身可以用于上传,所以不是read_only,但 avatar_url 是只读的。 # email 和 phone_number 通常不应通过这个接口随意更改,如果允许更改,需要额外的验证流程(比如发送验证码)。 def get_avatar_url(self, obj): request = self.context.get('request') if obj.avatar and hasattr(obj.avatar, 'url'): if request is not None: return request.build_absolute_uri(obj.avatar.url) return obj.avatar.url # Fallback if request is not available return None # 如果没有头像或无法获取URL # 如果允许通过这个Serializer更新头像,不需要特别做什么,DRF的ModelSerializer会自动处理ImageField # 确保在视图中传递 request 到 serializer context,以便生成完整的URL