Creating a Custom User Model

Before Django 1.5 the popular way to customize Django’s built-in User model was to introduce a Profile model with a OneToOne relationship with Django’s built-in User model.

Now it’s possible to do it using inheritance. This recipe will guide you on how to do it for a fresh Django project. While it’s possible to do it for an existing code base, the process is more involved so even if you think you don’t need it at the start of your project it’s a good idea to do this anyway. We hope to write a guide on that in the future.

For this recipe, we’ll use a new Django project named cookbook.

django-admin.py startproject cookbook

Once inside the generated directory you should see a directory named cookbook/ alongside a file named manage.py

Pretty standard stuff so far.

One thing I like to do is add my Django sub-apps inside the project’s namespace. For our custom User model, let’s put it inside the cookbook.users namespace. To do that we’ll need to create the cookbook/users/ directory first and then run the usual startapp command.

mkdir cookbook/users
./manage.py startapp users cookbook/users

Adding cookbook/users at the end of the startapp command tells Django to place the boilerplate code there. If it is unspecified, it will show up at the same level as cookbook/ and manage.py.

Don’t forget to update INSTALLED_APPS inside cookbook/settings.py.

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',

    'cookbook.users',
]

Custom User model that behaves exactly like Django’s builtin User model

Now it’s time to create our custom User model. If you don’t need to customize anything right now, but just want to specify a custom user model you can do so by inheriting from AbstractUser. This effectively gives you everything that’s already in Django’s builtin User model.

from django.contrib.auth.models import AbstractUser


class CookbookUser(AbstractUser):
    pass

Custom User model with, well, customizations

For our example, we’ll add created and modified timestamp fields to CookbookUser using TimeStampedModel from django-extensions.

There is also a TimeStampedModel from django-model-utils. There are pros and cons in choosing one package over the other, but for the purpose of this example both implementations are basically the same. I personally prefer using the implementation from django-extensions, because I also use the other things that come with it.

from django.contrib.auth.models import AbstractUser
from django_extensions.db.models import TimeStampedModel


class CookbookUser(TimeStampedModel, AbstractUser):
    pass

It looks the same - which is kind of the point. It’s now possible to specify custom fields and behavior using simple inheritance.

Telling Django to use our User model instead of the default one

At this point our Django project is still using django.contrib.auth.models.User as its user model. We can change this by specifying CookbookUser as our AUTH_USER_MODEL inside settings.py

# Custom user model is implemented inside cookbook/users/models.py
AUTH_USER_MODEL = 'users.CookbookUser'

At this point we can finally create the migrations for our new model.

./manage.py makemigrations

We now have our own custom User model. We can add even more changes in the future. This guide aims to teach you enough to have something usable and does not cover all the nuances of using a custom User model as well as the official documentation.

Django Admin

One problem you might run into is unhashed passwords for users created using the admin site.

Your admin.py for your custom user model might look something like this:

from django.contrib import admin

from .models import CookbookUser


admin.site.register(CookbookUser)

Since we ask Django to automatically create an admin page for CookbookUser, the code above treats the password field as just another text field so whatever you type in is saved verbatim in the database.

Custom behavior for this admin form was created in UserAdmin so we can set that as the admin class for our custom user model.

from django.contrib import admin
from django.contrib.auth.admin import UserAdmin

from .models import CookbookUser


admin.site.register(CookbookUser, UserAdmin)

If you found this useful and would like to get updates on new posts, please subscribe to our newsletter and follow us on Twitter @DjangoCookbook.