1.The User model, and swapping it for a custom one
django.contrib.auth.models.User is the default user model — username, email, password (hashed), first_name/last_name, is_staff/is_superuser/is_active, and groups/permissions. AUTH_USER_MODEL in settings.py points at whichever user model is actually in use; swapping it to a custom model (extending AbstractUser for a mostly-default shape, or AbstractBaseUser for a from-scratch one, e.g. email-only login) must happen BEFORE the first migration, since every other app's ForeignKey(User) actually resolves through this setting.
Key features
- AUTH_USER_MODEL (default "auth.User") is the single source of truth for which model is "the" user model — every internal Django reference goes through it, never a hardcoded import
- get_user_model() returns the actual active user model at runtime — this is the correct way to reference it in code, not `from django.contrib.auth.models import User`
- A ForeignKey to the user model should be written as settings.AUTH_USER_MODEL (a string, avoiding a circular import) — not a direct import of User, which breaks the moment AUTH_USER_MODEL is swapped
- AbstractUser extends the default fields/behavior (username, email, is_staff, etc.) — appropriate when the default shape is close to what's needed, just extended
- AbstractBaseUser provides only password hashing and the authentication API surface, no fields at all — appropriate for a from-scratch shape (e.g. email-only login, no username field)
- Swapping AUTH_USER_MODEL after the first migrate has already run against the default User is NOT a supported, low-risk operation — Django's own docs recommend deciding this before any migrations exist
AbstractUser vs AbstractBaseUser
- settings.py
- AUTH_USER_MODEL — "accounts.User"
- Django internals
- get_user_model()
- ForeignKey(settings.AUTH_USER_MODEL)
- accounts/models.py
- class User(AbstractUser)
Command
# settings.py
AUTH_USER_MODEL = "accounts.User"
# accounts/models.py
class User(AbstractUser):
...AUTH_USER_MODEL + get_user_model() is the indirection Django uses everywhere internally — never import User directly. Decide on a custom user model (AbstractUser for default-shape-plus-fields, AbstractBaseUser for a from-scratch shape) BEFORE the first migration; swapping later is not a safe, casual operation.