How to Configure a Custom User Model in Django

Ahmad Bilesanmi
Bilesanmi Ahmad
Published in
5 min readSep 21, 2020
Django Logo

Django is a very powerful web framework built for python developers with the aim of quickly building web applications using a concept called “Batteries included” where loads of features have been simplified within the framework.

In this tutorial, we are going to learn how to build a custom user model in Django. Why do we need to build a custom user model, what is wrong with the existing user model, you may ask. By default, Django’s user model requires a username and password to create a user. However, modern web applications would rather use email and password to create and verify users. This is because an email is unique to just one person and that email can be used to identify a particular user. A username method will result in either multiple users having the same username or users having undesired usernames. Another reason why the email method works better is that it also serves as a way to send messages to your users about updates on the application and other important information. Enough of the theory and let’s jump into some code.

This tutorial assumes you have virtualenv installed or some other way of creating a private environment for your project like docker and you are working from said environment.

Creating our project and app

Firstly, we would create our Django project called userproject and app called core using the following commands:

django-admin startproject userproject .
python manage.py startapp core

Add tests for the Custom User

In this section, we are going to create some tests for our custom user model. This method of writing test code before the actual code is referred to as Test Driven Development (TDD). It helps us to think of our code before writing it, thereby helping us write better quality code. Before writing our tests, we would add our core app to the settings.py file so the app can be recognized by the project.

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

Next, we add the following code to our test.py file in the core app

Line 1 starts with importing the TestCase class that will be used to create our test classes. Line 2 imports the get_user_model function which is used to get the user model for the project. get_user_model is a preferred way to import your User model class in case you decide to change it in the future, you don’t have to change it everywhere it was used. Line 5 creates the test class and inherits the TestCase class. Line 7 is where the test function is defined. Ensure to always start your test functions with the ‘test’, else it will not run when you are running your tests. Take note of the user.check_password() function on line 17. It is a helper function that returns True if the password passed to it matches the actual password. Lines 19–24 start a function that is used to test if the user’s email is normalized. Lines 26–29 create a function to check if a user object can be created without an email. Finally, lines 31–38 are used to test the creation of a superuser. Since we have not written the actual code for these tests, the tests would fail.

python manage.py test

Implement Custom User Model

In this section, we would be implementing the Custom User Model. We would be using classes such as AbstractBaseUser, BaseUserManager, and PermissionsMixin.

From line 2 we import the Django classes AbstractBaseUser, BaseUserManager, and PermissionsMixin. Note the backslash on line 2, it helps us to continue our code on the next line thereby helping us follow python’s coding style. Line 6 creates the UserManager class that extends the BaseUserManager. This extension will help us access and override attributes and methods of the superclass. Line 8 creates a method for creating a new user. Note on line 10, there is a check if the email is None or not a valid email, a ValueError is raised. Also, check out self.model on line 12, this refers to the User model that uses the manager class. So if the name of the User model is called CustomUser, that line is the same as CustomUser(email=self.normalize_email(email), **extra_fields). Also on line 12, we can see the method, self.normalize_email(). This function is inherited from the BaseUserManager class and its used to convert the text after the @ symbol in an email address to lowercase. Line 13 has the set_password method which is used to encrypt the password so your password is not visible in the database. Then we save the user to the database on line 14 and return the user on line 16.

Next, we have a method to create a superuser on line 18. Note that the superuser is usually created in the command line, so there is no need for **extra_fields. On line 19 we used the same method used above. This is a concept known as DRY (Don’t Repeat Yourself). On lines 20 and 21, we set the is_staff and is_superuser fields to True . We save the superuser to the database on line 22 and return the superuser on line 24.

Next, we have created the custom user model on line 27, and it's extending the AbstractBaseUser and PermissionsMixin classes. Lines 29 to 32 specify the fields we want to use in the custom model. Line 31 has the field is_active which is set to True so when a user is created, it becomes active. Line 32 has the field is_staff which is set to False. The is_staff field is used for admin accounts and so it is set to False by default. Line 34 sets the field objects to UserManager that was created earlier and so we can use the create_user method to create and save new users. Line 36 sets the field USERNAME_FIELD to 'email' so email becomes the unique identifier for the user model.

Now we go to the settings.py file and add AUTH_USER_MODEL = ‘core.User’ to the end of the file. You can adjust the value to fit your own project. core is the name of the app and User is the name of the model.

We can now run our migrations and tests again.

python manage.py makemigrations
python manage.py migrate
python manage.py test

This time Django will successfully run the four tests that we have written for our Custom User model. We now have a User model that uses only email and password for authentication.

I hope this helps you. Thanks for reading.

--

--

Ahmad Bilesanmi
Bilesanmi Ahmad

Software Engineer || Python || Javascript || DevOps || Data