Django Creating Custom User Model with Custom Authentication Backend
Table of Contents
- Setup Project
- Create App
- Create a Customer Manager for Model that extends BaseUserManager and Custom Model that extends AbstractBaseUser
- Change Default AUTH_USER_MODEL in settings
- Create Custom Authentication Backend
- Change Default AUTHENTICATION_BACKENDS to newly created one
- User Logging example
- Conclusion
Setup Project
Create a new project by typing command django-admin startproject user_model_test. user_model_test is just a project you can give it any other name you like.
Create App
- Go inside root directory and in terminal django-admin startapp custom_user this command creates a new app for the project.
- In project settings.py file installed app section register newly created app.
INSTALLED_APPS = [ '...', 'custom_user.apps.CustomUserConfig', ]
In settings.py specify database connection.
DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'user_model_test', 'USER': 'root', 'PASSWORD': '....', 'HOST': 'localhost', # Or an IP Address that your DB is hosted on 'PORT': '3306', 'OPTIONS': { 'sql_mode': 'traditional', } } }
Create a Customer Manager for Model that extends BaseUserManager and Custom Model that extends AbstractBaseUser
Open models.py file located in app custom_user. Create a custom user model that will replace the default authentication, user model.
from django.db import models from django.contrib.auth.models import ( BaseUserManager, AbstractBaseUser, AbstractUser ) # Create your models here. class CustomUserManager(BaseUserManager): def create_user(self, password, first_name, phone=None, last_name=None): if not phone: raise ValueError("User must have phone number") user = self.model( first_name = first_name, last_name = last_name, phone = phone ) user.set_password(password) user.save(using=self._db) return user def create_superuser(self, password, first_name, phone=None, last_name=None): user = self.create_user( first_name = first_name, last_name = last_name, phone = phone, password = password ) user.is_admin=True user.save(using=self._db) return user class CustomUser(AbstractBaseUser): id = models.AutoField(primary_key=True) first_name = models.CharField(max_length=150) last_name = models.CharField(max_length=150,null=True) email = models.EmailField(null=True) phone = models.CharField(max_length=150,unique=True) password = models.CharField(max_length=150) is_active = models.BooleanField(default=True) is_admin = models.BooleanField(default=False) created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) USERNAME_FIELD = 'phone' REQUIRED_FIELDS = ['first_name', 'last_name'] objects = CustomUserManager() def __str__(self): return "{} {}".format(self.phone, self.first_name) @property def is_staff(self): return self.is_admin @property def is_anonymous(self): return False @property def is_authenticated(self): return True class Meta(): db_table = 'auth_user' verbose_name = 'User' verbose_name_plural = 'Users'
The CustomUser
model inherits AbstractBaseUser
. We can specify all the important fields we require in our table.
In USERNAME_FIELD
you have specified phone
which means that we’ll be using phone
number to authenticate the user and log him into the system.
The REQUIRED_FIELDS
are necessary to assign as this will be asked by system when creating superuser
.
For the custom user model, it is mandatory to specify Custom Manager and assign it to objects variable objects = CustomUserManager()
with this, you can fetch objects from the model.
CustomUser.objects.create_user(**kwargs) #OR CustomUser.objects.create_superuser(**kwargs)
It is also important to specify property such are is_staff
, is_anonymous
, is_authenticated
these will be used by Django backend and also by us.
The Manager CustomUserManager
inherits BaseUserManager
and here we need to add two main methods create_user
and create_superuser
.
The Django Backend will make use of create_superuser
method while registering a new superuser.
Change Default AUTH_USER_MODEL in settings
Django does not know we have created a model that has to be used for authentication. To make Django use or custom model for authentication we must specify a path to our model in settings.py file.
In settings.py file add the below path.
AUTH_USER_MODEL = 'custom_user.CustomUser'
AUTH_USER_MODEL = ‘.’.
Create Custom Authentication Backend
In-app custom_user create backend.py it is in this file which you specify how to or custom way of user authentication.
We’ll return user object if phone and password matches else return None.
from django.conf import settings from django.contrib.auth.hashers import check_password from custom_user.models import CustomUser class CustomUserBackend: def authenticate(self,request,phone=None,password=None): if phone and password: try: user = CustomUser.objects.get(phone=phone) if check_password(password,user.password): if user.is_active: return user except CustomUser.DoesNotExist: return None return None def get_user(self,user_id): try: return CustomUser.objects.get(pk=user_id) except CustomUser.DoesNotExist: return None
In class CustomUserBackend
it is mandatory to specify authenticate()
and get_user()
method.
In authenticate()
we pass arguments such as request
the object is mandatory as the authenticated user data will be stored their phone and password for verification.
Change Default AUTHENTICATION_BACKENDS to newly created one
We are just a step behind. Now we have created CustomUserBackend
we’ll inform Django to use this backend insisted on default.
To do that go to settings.py file and add the below code.
AUTHENTICATION_BACKENDS = ['custom_user.backend.CustomUserBackend','django.contrib.auth.backends.ModelBackend']
User Logging example
In order to make you completely understand below, we have an example of a user logging system with all codes.
In custom_user/models.py
from django.db import models from django.contrib.auth.models import ( BaseUserManager, AbstractBaseUser, AbstractUser ) # Create your models here. class CustomUserManager(BaseUserManager): def create_user(self, password, first_name, phone=None, last_name=None): if not phone: raise ValueError("User must have phone number") user = self.model( first_name = first_name, last_name = last_name, phone = phone ) user.set_password(password) user.save(using=self._db) return user def create_superuser(self, password, first_name, phone=None, last_name=None): user = self.create_user( first_name = first_name, last_name = last_name, phone = phone, password = password ) user.is_admin=True user.save(using=self._db) return user class CustomUser(AbstractBaseUser): id = models.AutoField(primary_key=True) first_name = models.CharField(max_length=150) last_name = models.CharField(max_length=150,null=True) email = models.EmailField(null=True) phone = models.CharField(max_length=150,unique=True) password = models.CharField(max_length=150) is_active = models.BooleanField(default=True) is_admin = models.BooleanField(default=False) created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) USERNAME_FIELD = 'phone' REQUIRED_FIELDS = ['first_name', 'last_name'] objects = CustomUserManager() def __str__(self): return "{} {}".format(self.phone, self.first_name) @property def is_staff(self): return self.is_admin @property def is_anonymous(self): return False @property def is_authenticated(self): return True class Meta(): db_table = 'auth_user' verbose_name = 'User' verbose_name_plural = 'Users'
In custom_user/backend.py.
from django.conf import settings from django.contrib.auth.hashers import check_password from custom_user.models import CustomUser class CustomUserBackend: def authenticate(self,request,phone=None,password=None): if phone and password: try: user = CustomUser.objects.get(phone=phone) if check_password(password,user.password): if user.is_active: return user except CustomUser.DoesNotExist: return None return None def get_user(self,user_id): try: return CustomUser.objects.get(pk=user_id) except CustomUser.DoesNotExist: return None
In settings.py file
AUTH_USER_MODEL = 'custom_user.CustomUser' AUTHENTICATION_BACKENDS = ['custom_user.backend.CustomUserBackend','django.contrib.auth.backends.ModelBackend']
In urls.py
from django.contrib import admin from django.urls import path, include urlpatterns = [ path('admin/', admin.site.urls), path('custom_user/', include('custom_user.urls')), ]
In custom_user/urls.py
from django.urls import path, re_path from custom_user import views app_name="custom_user" urlpatterns = [ path('login', views.log_in, name="login"), path('login/verify', views.verify_login, name="login-verify"), path('logout', views.log_out, name="logout"), path('home', views.home, name="home"), ]
In custom_user/views.py
from django.shortcuts import render, redirect from django.http import HttpResponse from django.contrib.auth import authenticate, login, logout from django.contrib.auth.decorators import login_required from django.urls import reverse # Create your views here. def log_in(request): template="custom_user/login.html" context={} return render(request,template,context) def verify_login(request): phone = request.POST['phone'] password = request.POST['password'] user = authenticate(request, phone=phone, password=password) if user is not None: login(request, user) # Redirect to a success page. return redirect(reverse("custom_user:home")) else: return redirect(reverse("custom_user:login")) def log_out(request): logout(request) return redirect(reverse("custom_user:login")) @login_required(login_url='custom_user:login') def home(request): template="custom_user/home.html" context={} return render(request,template,context)
In custom_user/templates/custom_user/login.html
<h2>Login</h2> <form action="{% url 'custom_user:login-verify' %}" method="post"> {% csrf_token %} <label for="">Phone No*</label> <input type="text" name="phone" value=""> <hr> <label for="">Password*</label> <input type="password" name="password" value=""> <hr> <input type="submit" value="Login"> </form>
In custom_user/templates/custom_user/home.html
<h1>Welcome to Home</h1> <a href="{% url 'custom_user:logout' %}">Logout</a>
Conclusion
We have come to the final part of our post on Django Creating Custom User Model with Custom Authentication Backend. For any suggestions and queries comment below.
Recent Posts




