Every new Django project should use a custom user model. The official Django documentation says it is “highly recommended” but I’ll go a step further and say without hesitation: You are straight up crazy not to use a custom user model up front.

Why? Because you will need to make changes to User at some point in your project’s life–adding a date of birth field, an age, anything–and if you have not started with a custom user model from before the very first migrate command you run, then you’re in for a world of hurt.

However if you do use a custom user model, you can make additions and modifications very easily.

Is it possible to switch over to a custom user model mid-project? Yes. Do you want to do it? Heck no.

Here is the simplest way I know to start every new project off the right way.

Step 1: Create a new project

On the command line, navigate to a new directory for your code, use Pipenv to install Django, activate the virtual environment, and create a new project called new_project. Let’s assume we want to use a code folder on the Desktop since I’m on a Mac.

$ cd ~/Desktop
$ mkdir code && cd code
$ pipenv install django
$ pipenv shell
(code) $ django-admin startproject new_project .

Now we need to create a users app and then update 4 files. Ready?

Step 2: Create a users app

(code) $ python manage.py startapp users

Now let’s tell Django about the new app and update AUTH_USER_MODEL so that Django knows to use our new CustomUser model instead of the default User model.

Open up new_project/settings.py with your text editor and make these two changes:

# new_project/settings.py
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',

    # Local
    'users.apps.UsersConfig', # new
]
...
AUTH_USER_MODEL = 'users.CustomUser' # new

Step 3. CustomUser model

We want to extend (or copy) the existing User model and call it something else, in our case CustomUser. That’s all we need to do. Just make a copy and then we can tweak it around as we like while still taking advantage of all of User’s built-in goodness.

We don’t even need to add a field at this point!

# users/models.py
from django.contrib.auth.models import AbstractUser
from django.db import models

class CustomUser(AbstractUser):
    # add additional fields in here

Step 4: Update User Forms

Django uses the User model–now our CustomUser model since we told it to in AUTH_USER_MODEL all over the place. Two major places are when a new user is created and when we change something about a user. So we have to again extend the built-in forms for this and point them to our new CustomUser model.

Create a new users/forms.py file and fill it with the following:

# users/forms.py
from django import forms
from django.contrib.auth.forms import UserCreationForm, UserChangeForm
from .models import CustomUser

class CustomUserCreationForm(UserCreationForm):

    class Meta(UserCreationForm):
        model = CustomUser
        fields = ('username', 'email')

class CustomUserChangeForm(UserChangeForm):

    class Meta:
        model = CustomUser
        fields = ('username', 'email')

Step 5: Update admin.py

The Django User model is highly coupled with the excellent built-in admin app so we need to tell Django to use CustomUser instead. Here’s how:

# users/admin.py
from django.contrib import admin
from django.contrib.auth import get_user_model
from django.contrib.auth.admin import UserAdmin

from .forms import CustomUserCreationForm, CustomUserChangeForm
from .models import CustomUser

class CustomUserAdmin(UserAdmin):
    add_form = CustomUserCreationForm
    form = CustomUserChangeForm
    model = CustomUser
    list_display = ['email', 'username',]

admin.site.register(CustomUser, CustomUserAdmin)

Done!!!

And that’s it. We’re done. Create a migrations file for our changes and then run migrate for the first time to initialize our database with CustomUser in place of User.

(code) $ python manage.py makemigrations users
(code) $ python manage.py migrate

Congratulations! You’ve future-proofed your Django project and can proceed without issue.




Interested in learning more Django? I’ve written 3 books!