bigywater.tech
Django · 75

自定义 User Model 的正确时机

官方文档说「一开始就用自定义 User」。晚了到底会怎样?这篇分别做「一开始就自定义」「已迁移后再切换」「只加字段用 Profile」三种情形,把报错原文和数据库状态摆出来。

第一次 migrate 之前
AUTH_USER_MODEL 要在第一次 migrate 之前设置;之后切换会 InconsistentMigrationHistory
没有 auth_user
一开始就自定义时,库里只有 lab_user
Profile
只想加字段、不改认证行为时,OneToOne Profile 不需要换 User

从头就自定义

实测 · 本机执行输出
  makemigrations: ["Migrations for 'lab':", 'lab/migrations/0001_initial.py', '+ Create model User']
  migrate rc = 0  最后一行:   Applying sessions.0001_initial... OK
  get_user_model() = lab.models.User  表名 = lab_user
  是否还有 auth_user 表: False
  自定义字段: 1

所有指向用户的外键都要写 settings.AUTH_USER_MODEL(字符串),代码里取模型用 get_user_model(),不要直接 from django.contrib.auth.models import User。

中途替换

实测 · 本机执行输出
   默认 User 里已有用户: 1
  换成 lab.User 之后 makemigrations:     + Create model User
  migrate: django.db.migrations.exceptions.InconsistentMigrationHistory: Migration admin.0001_initial is applied before its dependency lab.0001_initial on database 'default'.
   表: ['auth_user', 'auth_user_groups', 'auth_user_user_permissions']

报错的原因:admin 等应用的迁移依赖了用户模型(settings.AUTH_USER_MODEL),已经在默认 User 上应用过;换了之后依赖顺序被破坏。原有 auth_user 表和数据没有自动搬到新表。

Profile 扩展

实测 · 本机执行输出
  migrate rc = 0
  u.profile.phone = 1

代价是多一次 JOIN 或查询(可用 select_related,第 28 篇)。

分步演示:何时换 User

自定义 User Model
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 / Python 3.14.7 / Django 6.1.1(默认用 SQLite,其它数据库会在文中注明),用 django.test.Client 或真实的本机服务器进程实测;计时用 time.perf_counter,数字每次运行会有小幅抖动。SQLite;项目里装了 admin / sessions / messages(admin 的检查要求相应的中间件与上下文处理器,已配置)
    • 没有验证:中途安全迁移到自定义 User 的做法(手工改迁移 / 重命名表)、AbstractBaseUser 从零实现、USERNAME_FIELD 为邮箱、swappable 模型的其它影响、与第三方 app 的兼容
    京ICP备2026067502号-1京公网安备11010502063487号