Django Rest Framework用户创建异常:后台提示密码格式无效
咱们先逐个拆解你的三个实现,找出问题所在:
1. views3.py:直接用User.objects.create(**validated_data)——最明显的错误
这个方法会把validated_data里的明文密码直接存入数据库,而Django的认证系统要求密码必须是经过哈希处理的字符串(格式类似pbkdf2_sha256$320000$xxxxxx)。明文密码完全不符合这个规范,所以管理面板必然会报错。
2. views1.py:返回validated_data而非用户实例——违反DRF规范
你的create方法逻辑前半段是对的:创建用户实例、调用set_password()哈希密码、保存到数据库,但最后返回的是validated_data字典,而不是创建好的user_obj实例。
DRF的ModelSerializer要求create方法必须返回创建的模型实例,虽然这个错误不会直接导致密码哈希失效,但会破坏Serializer的正常工作流程,甚至可能在后续操作中引发异常(比如序列化返回数据时出错)。
3. views2.py:逻辑正确,但可能存在隐藏问题
这个实现本身没问题:先通过User(**validated_data)初始化实例,再调用set_password()哈希密码,最后保存。但如果你的自定义User模型对应的UserManager没有正确重写,就可能出问题——因为你把USERNAME_FIELD设为email,还移除了默认的username字段,默认的UserManager是为username设计的,必须重写适配你的自定义模型。
关键修复:重写自定义User模型的Manager
你需要给customuser.User配上正确的UserManager,否则即使调用了set_password,也可能在某些场景下(比如创建超级用户)出现异常。示例代码如下:
from django.contrib.auth.models import BaseUserManager class UserManager(BaseUserManager): def create_user(self, email, phone, password=None, **extra_fields): if not email: raise ValueError('必须设置邮箱字段') email = self.normalize_email(email) user = self.model(email=email, phone=phone, **extra_fields) user.set_password(password) user.save(using=self._db) return user def create_superuser(self, email, phone, password=None, **extra_fields): extra_fields.setdefault('is_staff', True) extra_fields.setdefault('is_superuser', True) if extra_fields.get('is_staff') is not True: raise ValueError('超级用户必须设置is_staff=True') if extra_fields.get('is_superuser') is not True: raise ValueError('超级用户必须设置is_superuser=True') return self.create_user(email, phone, password, **extra_fields)
然后在你的User模型里关联这个Manager:
class User(AbstractUser): # ... 你的字段定义 ... objects = UserManager()
推荐的正确Serializer实现
结合上面的分析,优化后的create方法应该是这样的(既严谨又符合DRF规范):
class UserCreateSerializer(ModelSerializer): class Meta: model = User fields = ['email', 'phone', 'password'] extra_kwargs = {"password": {"write_only": True}} def create(self, validated_data): # 先把密码从validated_data中取出,避免直接传给User构造器 password = validated_data.pop('password') user = User(**validated_data) user.set_password(password) # 哈希密码 user.save() return user # 返回创建好的用户实例
额外修复:settings.py的重复配置
你的settings.py里写了两个REST_FRAMEWORK字典,第二个会完全覆盖第一个,导致你的认证类配置失效。合并成一个字典即可:
REST_FRAMEWORK = { 'DEFAULT_AUTHENTICATION_CLASSES': ( 'rest_framework.authentication.BasicAuthentication', 'rest_framework.authentication.SessionAuthentication', ), 'DEFAULT_PERMISSION_CLASSES': [ 'rest_framework.permissions.AllowAny', ] }
最后一步:清理旧数据
如果你之前用views3创建过用户,数据库里会有明文密码的用户记录,这些记录会一直触发管理面板的报错。你需要删除这些用户,或者通过管理面板重置他们的密码(重置时Django会自动哈希)。
内容的提问来源于stack exchange,提问作者Jekson

