Changing the user model after the first migration is painful, so it's a day-one decision.
Django's docs recommend that every new project define a custom user model, even an empty one, because switching later means rewriting migrations and foreign keys across apps.
The easy version extends AbstractUser, keeping username, password, permissions and the admin integration:
class User(AbstractUser):
passand in settings: AUTH_USER_MODEL = "accounts.User", set before the first migrate.
To log in with email instead of a username, either keep AbstractUser and set USERNAME_FIELD = "email" with a unique email field and REQUIRED_FIELDS = [] (also removing the username field), or build on AbstractBaseUser and PermissionsMixin with a custom manager implementing create_user and create_superuser.
Referencing the user model correctly:
- in model fields:
models.ForeignKey(settings.AUTH_USER_MODEL, ...) - in other code:
get_user_model()returns the active class - never
from django.contrib.auth.models import Userin reusable code
Register it in the admin with admin.site.register(User, UserAdmin) (or a UserAdmin subclass with your fields).
For extra per-user data that isn't needed for authentication, such as a bio or preferences, a separate Profile model with a OneToOneField to the user keeps the user table lean, and can be added at any time.
Example
# accounts/models.py
from django.contrib.auth.models import AbstractUser, UserManager
from django.db import models
class EmailUserManager(UserManager):
def _create_user(self, email, password, **extra):
user = self.model(email=self.normalize_email(email), **extra)
user.set_password(password)
user.save(using=self._db)
return user
def create_user(self, email, password=None, **extra):
return self._create_user(email, password, **extra)
def create_superuser(self, email, password=None, **extra):
return self._create_user(email, password, is_staff=True, is_superuser=True, **extra)
class User(AbstractUser):
username = None
email = models.EmailField(unique=True)
USERNAME_FIELD = "email"
REQUIRED_FIELDS = []
objects = EmailUserManager()
# settings.py (before the first migrate!)
AUTH_USER_MODEL = "accounts.User"
# elsewhere: author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)Remember
- Define a custom user model at project start; set AUTH_USER_MODEL before the first migration
- Extend AbstractUser for the easy path
- Reference users via settings.AUTH_USER_MODEL and get_user_model()
Watch out for
- Importing django.contrib.auth.models.User directly in apps, which breaks with a custom user model.