Django Tips #6: Custom User Model
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.
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
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
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)
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
(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!