By default, Django uses a built-in User model for authentication. If you’d like a basic tutorial on how to implement login, log out, sign up you can see the Django Authentication SignUpView -LoginView-LogoutView

However, the Django documentation highly recommends using a custom user model for a real-world project. Because this provides far more flexibility. In todays’ article, we will see how to create a custom user model for Django projects.

The default User model in Django uses a username to uniquely identify a user during authentication. We can create a custom Django user model by either subclassing AbstractUser or AbstractBaseUser. The difference is AbstractUser uses the existing fields of the User model and just allows to remove the username field.

On the contrary, AbstractBaseUser is used if one wants to start from scratch by creating completely a new User model. Here we will use  AbstractBaseUser

Firstly, we have created a Django project called ‘CUSTOM_AUTHENTICATION’ and an app named ‘custom_auth’. Now we are all set to start our work. So, without further ado let’s create our CustomUser model first.

Custom User Model

from django.db import models
from django.contrib.auth.models import AbstractBaseUser, BaseUserManager

# Create your models here.
class CustomUser(AbstractBaseUser):
    """
    AbstractBaseUser provides core functionalities of 
    a user authenticatin system like password hashing, 
   session storing, 
    recognizing, tokenizing, password reset and
    and all those functionalities.
    """
    username = models.CharField(max_length=20,unique=True)
    email = models.EmailField(verbose_name="Email Address", max_length=60, unique=True)
    phone = models.PositiveIntegerField(null=True,blank=True)
    date_joined = models.DateTimeField(auto_now_add=True)
    last_login = models.DateTimeField(verbose_name='last login', auto_now= True)

    is_admin = models.BooleanField(default=False)
    is_active = models.BooleanField(default=True)
    is_staff = models.BooleanField(default=False)
    is_superuser = models.BooleanField(default=False)

    # this constant defines which field 
    # will be used as username as login credential
    USERNAME_FIELD = "email"
    
    REQUIRED_FIELDS = ['username',]

    # This manager will take care of each
    # object of this model before creation 
    objects = CustomUserManager()

    def __str__(self):
        return self.username

    def has_perm(self, perm, obj=None):
        return True

    def has_module_perms(self, app_label):
        return True

In settings.py we’ll register the 'custom_auth' app in INSTALLED_APPS  and use the AUTH_USER_MODEL config to tell Django to use our new CustomUser model in place of the built-in User model.

AUTH_USER_MODEL = 'custom_auth.CustomUser'

# Application definition

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    
    # my apps
    'custom_auth',
]

Here we have Created a new class called CustomUser that subclasses AbstractBaseUser and Added fields for email, username, phone,  is_staff, is_active, is_admin, is_superuser,  and date_joined and last_login. Though both email and username  are unique fields, we will user email as our username field.  So, we will have to set the USERNAME_FIELD to email.

Then we have Specified that all objects for the class come from the CustomUserManager We will create this now.

Custom User Manager

The CustomUserManager will be subclassing BaseUserManager. It uses an email as the unique identifier instead of a username. We can place CustomUserManager inside a managers.py file in the “custom_user” directory or we can place it inside models.py but it must be placed before the model.

class CustomUserManager(BaseUserManager):

    def create_user(self, email, username, phone=None, password=None):
        if not email:
            raise ValueError('Email is required')
        if not username:
            raise ValueError('Username is required')
        if not password:
            raise ValueError("Password is required")
        
        # create user object
        user = self.model(
            email=self.normalize_email(email),
            username = username,
            phone = phone,
        )
        user.set_password(password)
        user.save(using=self._db)
        return user

    def create_superuser(self, email, username, password=None):
        
        user = self.create_user(
            email=self.normalize_email(email),
            username=username,
            password=password,
        )
        user.is_admin = True
        user.is_staff = True
        user.is_superuser = True
        user.save(using=self._db)

        return user

Everything is set to run migrations. After running migrations, we will have our CustomUser table in our database. But we will have to register it on admin site for getting a visual representation. Let’s register it on the admin site.

admin.py

from django.contrib import admin
from .models import CustomUser

# Register your models here.
class CustomUserAdmin(admin.ModelAdmin):
    list_display = ['email', 'username', 'is_active']

admin.site.register(CustomUser, CustomUserAdmin)

Still, we don’t have any CustomUser object. We will create a super user first by running this command… (Virtual Environment must be activated)

python manage.py createsuperuser

We must give the required credentials.

(env) PS E:\Django\project\custom_authentication> python manage.py createsuperuser
Email Address: admin@gmail.com
Username: admin
Password:
Password (again):
The password is too similar to the username.
This password is too short. It must contain at least 8 characters.
This password is too common.
Bypass password validation and create user anyway? [y/N]: y
Superuser created successfully.

Django created a Superuser (admin) successfully. Let’s run the server and log in to the Django admin panel.

Existing Objects:

Add New User

+ posts

Author | Python-Django Developer

+ posts

Full-stack Developer (Python | Django | React | React-Native | Angular | Vue)