最稳妥的用户模型扩展方式是用 OneToOneField 关联,而非继承 User;密码应通过 create_user 或 set_password 自动生成,禁止手动调用 make_password;扩展字段需在表单中显式声明并重写 save 方法。
为什么不能直接继承
模型做注册扩展
因为 Django 的
模型是抽象基类(
)的封装,硬继承会导致迁移冲突、admin 不兼容、认证逻辑断裂。最稳妥的方式是用
关联,或从头自定义
—— 但后者要重写登录、管理命令、admin 注册等一堆东西,90% 的项目没必要。
实操建议:
用
扩展:适合只需要加几个字段(如昵称、头像、手机号)的场景,兼容所有内置认证流程
用
+
:仅当你需要改邮箱登录、禁用用户名、或彻底重构用户标识逻辑时才选
别碰
继承:它和默认
表结构高度耦合,迁移后容易爆
不该在视图里手动调用
Django 的
和
方法内部已经自动调用
,手动再套一层会导致密码被双重哈希,登录永远失败。典型错误现象是:注册成功,但
返回
,后台查
字段会发现值以
开头两次。
正确做法:
注册逻辑中,统一走
如果用了自定义用户模型,确保你的
方法里调用了
(不是
),再
绝对不要在表单
或视图里写
—— 这等于绕过 Django 密码策略(比如 salt 长度、迭代次数)
扩展字段怎么进注册表单又不破坏
默认只管
、
、
。想加
或
,不能靠覆盖
简单追加,否则
和保存逻辑会漏掉新字段。
Python 网站开发之Django环境搭建 WORD版
本文档主要讲述的是Python 网站开发之Django环境搭建;希望本文档会给有需要的朋友带来帮助;感兴趣的朋友可以过来看看
下载
实操要点:
继承
,在
指向你的扩展模型(如
)前,先确认该模型是否已通过
关联
把扩展字段声明在表单类体里(非
),例如:
重写
方法:先调
得到
实例,再用它创建关联的扩展模型实例(注意传
)
如果扩展字段存在唯一性约束(如
),必须在表单
里查库校验,不能只靠模型层
—— 因为
和扩展模型是两张表
密码加密强度由
决定,不是
参数
有人以为调
能指定算法,其实 Django 80% 的密码哈希行为由
控制。手动传算法名不仅多余,还可能降级安全强度(比如误用
)。
关键事实:
的第三个参数是“强制使用某 hasher”,仅用于测试或迁移旧密码,生产环境不该出现
当前 Django 默认用
,迭代次数由
中 hasher 类的
属性控制(默认 360000+)
改密钥轮数?别动
,去重写 hasher 类或调整
里的配置项
验证密码永远用
,它自动识别 hasher 类型,不需要你解析
字符串前缀
最容易被忽略的是:自定义用户模型的
方法是否真的调用了
或
—— 有些手写的
忘了这一行,导致明文存库。
UserUserAbstractBaseUserOneToOneFieldAbstractBaseUserOneToOneFieldAbstractBaseUserPermissionsMixinAbstractUserUserdjango.db.utils.ProgrammingError: relation "auth_user" already existsmake_passwordcreate_usercreate_superusermake_passwordauthenticate(username=..., password=...)NoneUser.passwordpbkdf2_sha256$User.objects.create_user(username=..., email=..., password=...)create_useruser.set_password(password)make_passworduser.save()save()user.password = make_password(raw)UserCreationFormUserCreationFormusernamepassword1password2emailphoneMeta.fieldsclean()UserCreationFormMeta.modelCustomUserProfileOneToOneFieldUserMetaemail = forms.EmailField(required=True)save()super().save()Useruser=userphoneclean()unique=TrueUserPASSWORD_HASHERSmake_passwordmake_password(raw, salt, 'pbkdf2_sha256')settings.PASSWORD_HASHERSmd5make_passwordPBKDF2PasswordHasherPASSWORD_HASHERSiterationsmake_passwordsettings.PASSWORD_HASHERScheck_password(raw, hashed)hashedset_passwordBaseUserManager.make_random_passwordhashers.make_passwordcreate_user