Custom User Model
Django provides a built-in authentication system with a default User model. This model includes basic fields like username, password, email and first name. However, most real-world applications require more information about their users such as a profile picture, a phone number, or a specific role.
Django gives you two main ways to handle this. You can either extend the existing model or substitute it entirely.
Extending the existing User model
There are two ways to extend the default User model. The approach you choose depends on whether you need to change the model's behavior or store additional data.
Proxy Models (Behavioral Changes)
If the changes you need are purely behavioral and do not require adding new columns to the database, you can create a proxy model based on the User model. This allows you to add custom methods, change the default ordering, or assign custom managers without altering the underlying database table.
from django.contrib.auth.models import User
class Person(User):
class Meta:
proxy = True
ordering = ("last_name", "first_name")
def get_full_name_upper(self):
return self.get_full_name().upper()Model with OneToOneField
If your project is already in progress and you’ve applied initial database migrations, the safest and most practical way to store additional user-related data is to create a separate model linked to the User via a OneToOneField. This related model is often referred to as a "Profile" model.
from django.db import models
from django.contrib.auth.models import User
class EmployeeProfile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
department = models.CharField(max_length=100)
employee_id = models.CharField(max_length=20)IMPORTANT
Profile models are not auto-created. You can create/update them with a post_save signal if you want that behavior.
Once this model is created, you can access the related information using standard Django relationship queries. If you have a user instance, you can simply call the related lowercase model name to get the extra data.
# Fetch the default User object
u = User.objects.get(username="fsmith")
# Access the related Employee profile data
print(u.employeeprofile.department)To add a profile model’s fields to the user page in the admin UI, refer to this Official doc.
NOTE
The profile model approach is very easy to add to existing projects and keeps the default User model intact. However, it requires an extra database JOIN to access profile data. Although a custom user model can be more efficient, the simplicity and lower risk of adding a profile model to an existing project often outweigh the small performance cost.
Substituting a Custom User model
If you are starting a brand new project, the official Django documentation strongly recommends setting up a custom user model before you run your first database migration. Substituting the default model allows you to store all user data in a single database table, which makes your database queries faster and your code cleaner.
Choosing the Base Class
Django offers two base classes to build your custom user model. Your choice depends on how much control you need over the authentication process.
AbstractUser
AbstractUser class retains all the default fields from Django's built-in User model (such as first name, last name, username and email). You simply subclass it and add your extra fields. This is the best choice if you are happy with the default authentication process but just need a few extra columns.
# models.py
from django.contrib.auth.models import AbstractUser
from django.db import models
class CustomUser(AbstractUser):
department = models.CharField(max_length=100)
employee_id = models.CharField(max_length=20)AbstractBaseUser
AbstractBaseUser class is completely barebones. It only provides the core authentication functionality, password hashing and a last login field. You must define all other fields yourself, including the specific identifier used for logging in. This is the ideal choice if you want complete control, such as using an email address as the primary login credential instead of a username.
When using AbstractBaseUser, you must define a few specific attributes so Django knows how to handle your users. You need to set the USERNAME_FIELD to the name of the field used for logging in. You also need to define a list of REQUIRED_FIELDS for when a user is created via the terminal.
Writing a Custom Manager
If you substitute the user model and change the primary login field (like switching from a username to an email address), Django's default user manager will no longer work. You must create a custom manager by sub-classing BaseUserManager.
In this manager, you are required to define two methods. The create_user() method handles standard user creation, while create_superuser() is used by the management console to create administrative accounts.
from django.contrib.auth.models import BaseUserManager
class CustomUserManager(BaseUserManager):
def create_user(self, email, password=None, **extra_fields):
if not email:
raise ValueError("The Email field must be set")
email = self.normalize_email(email)
user = self.model(email=email, **extra_fields)
user.set_password(password)
user.save(using=self._db)
return user
def create_superuser(self, email, password=None, **extra_fields):
extra_fields.setdefault("is_staff", True)
extra_fields.setdefault("is_superuser", True)
return self.create_user(email, password, **extra_fields)Defining the Model
Once your manager is ready, you can define your custom user model. Here is an example of an email-based user:
from django.contrib.auth.models import AbstractBaseUser, PermissionsMixin
from django.db import models
class CustomUser(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(unique=True)
department = models.CharField(max_length=100)
# Link the custom manager
objects = CustomUserManager()
USERNAME_FIELD = "email"
REQUIRED_FIELDS = ["department"]
def __str__(self):
return self.emailConfiguring the Project
After creating your custom model, you must tell Django to use it instead of the default one. You do this by adding the AUTH_USER_MODEL variable to your settings.py file.
# settings.py (`myapp` must be in `INSTALLED_APPS`)
AUTH_USER_MODEL = 'myapp.CustomUser'Because your project is now using a custom model, you should never import the default User model directly. Instead, Django provides a helper function called get_user_model() that automatically returns the currently active user model.
from django.contrib.auth import get_user_model
User = get_user_model()
user = User.objects.get(username="fsmith")When defining relationships to the user model in your other apps, it is generally easiest to reference the AUTH_USER_MODEL setting in code executed at import time. However, it is also completely valid to call get_user_model() while Django is importing models.
from django.conf import settings
from django.contrib.auth import get_user_model
from django.db import models
class Article(models.Model):
# Approach 1: Using the settings string (Most common)
author = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
)
# Approach 2: Evaluating the model directly
editor = models.ForeignKey(
get_user_model(),
on_delete=models.CASCADE,
)Registering in the Admin
Your custom user model will not appear in the Django admin interface automatically. You need to register it in your app's admin.py file.
If you used AbstractUser, you can simply reuse Django's existing UserAdmin class. If you used AbstractBaseUser, you will need to define a custom ModelAdmin to explicitly specify which fields should be displayed.
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from .models import CustomUser
admin.site.register(CustomUser, UserAdmin)