Hello everyone. Follow this article to understand about custom user model in Django.
I've attached the source code at the end of this article.
Django's built-in User model is good enough for many cases while also having a room for customization. Why would you need to tweak some of the functionalities of the default User model?
- Maybe you want to make
emailfield the primary unique identifier of users instead ofusername. - Maybe you want to include other unique fields for authentication like phone number.
- Maybe you want to stack all user information, be it auth related or non-auth fields all in the
Usermodel.
That being said, let's get to it.
Step 1: Set up a Django project.
1) Create a python virtual environment and activate it.
2) Install Django and Django rest framework.
pip install django djangorestframework
3) Start a new project:
django-admin startproject config .
4) Run the following command to see if the installation is correct.
py manage.py runserver
Note: Do not create and apply migrations because changing the
Usermodel after you’ve created database tables is significantly more difficult since it affects foreign keys and many-to-many relationships.
Now, create a new app users and add it to installed apps.
py manage.py startapp users
settings.py
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
# Third-party apps
'rest_framework',
# Local apps
'users',
]
When you have projects that require a different authentication that the built-in User model can’t provide, you have to create your own custom User model by extending from either AbstractUser or AbstractBaseUser Now, the question is which one should you extend from?
-
AbstractUser: Are you satisfied with the existing fields in the built-inUsermodel but you want to use email as the primary unique identifier of your users or perhaps remove theusernamefield? If yes,AbstractUseris the right option for you. -
AbstractBaseUser: There are two things to consider whenever starting a new project :-
Usermodel focused on authentication, and another model likeProfilethat keeps app-related information of the user. Here you may useAbstractBaseUserif you have additional auth-related attributes that you want to include in yourUsermodel. -
Usermodel that stores all information (auth related or non-auth attributes) all in one. You may want to do this to avoid using additional database queries to retrieve related model. If you want to take this approach,AbstractBaseUseris the right option.
-
Note: If you’re starting a new project, it’s highly recommended to set up a custom user model, even if the default
Usermodel is sufficient for you. This model behaves identically to the default user model, but you’ll be able to customize it in the future if the need arises:
from django.contrib.auth.models import AbstractUser
class User(AbstractUser):
pass
For the purpose of this article, we are going to use AbstractUser but the steps for AbstractBaseUser are also similar.
Step 2: Custom Model Manager
Manager is a class that provides an interface through which database query operations are provided to Django models. You can have more than one manager for your model.
Consider this model:
from django.db import models
class Car(models.Model):
pass
- To get all instances of
Car, you will useCar.objects.all()
objects is the default name that Django managers use. To change this name:
from django.db import models
class Car(models.Model):
cars = models.Manager();
Now, to get all instances of car, you should use Car.cars.all().
For our custom user model, we need to define a custom manager class because we are going to modify the initial Queryset that the default Manager class returns. We do this by extending from BaseUserManager and providing two additional methods create_user and create_superuser.
- Create a file named managers.py inside users app and put the following.
managers.py
from django.contrib.auth.base_user import BaseUserManager
from django.utils.translation import gettext as _
class CustomUserManager(BaseUserManager):
"""
Custom user model manager where email is the unique identifier
for authentication instead of usernames.
"""
def create_user(self, email, password, **extra_fields):
if not email:
raise ValueError(_('Users must have an email address'))
email = self.normalize_email(email)
user = self.model(email=email, **extra_fields)
user.set_password(password)
user.save()
return user
def create_superuser(self, email, password, **extra_fields):
extra_fields.setdefault('is_staff', True)
extra_fields.setdefault('is_superuser', True)
extra_fields.setdefault('is_active', True)
if extra_fields.get('is_staff') is not True:
raise ValueError(_('Superuser must have is_staff=True.'))
if extra_fields.get('is_superuser') is not True:
raise ValueError(_('Superuser must have is_superuser=True.'))
return self.create_user(email, password, **extra_fields)
Step 3: The User Model
models.py
from django.contrib.auth.models import AbstractUser
from django.db import models
from django.utils.translation import gettext as _
from .managers import CustomUserManager
class CustomUser(AbstractUser):
email = models.EmailField(_('email address'), unique=True)
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ('username',)
objects = CustomUserManager()
def __str__(self):
return self.email
-
USERNAME_FIELDspecifies the name of the field on the user model that is used as the unique identifier. In our case it’s email. -
REQUIRED_FIELDSA list of the field names that will be prompted for when creating a superuser via thecreatesuperusermanagement command. This doesn’t have any effect in other parts of Django like when creating a user in the admin panel.
Step 4: The Settings
We now have to tell Django our new model that should be used to represent a User. This is done as follows.
settings.py
AUTH_USER_MODEL = 'users.CustomUser'
→ You can now create and apply migrations.
py manage.py makemigrations
py manage.py migrate
Step 5: Forms
Django’s built-in UserCreationForm and UserChangeForm forms must be extended to let them know the new user model that we are working with.
Create a file named forms.py inside users app and add the following:
forms.py
from django.contrib.auth.forms import UserCreationForm, UserChangeForm
from .models import CustomUser
class CustomUserCreationForm(UserCreationForm):
class Meta:
model = CustomUser
fields = ('email',)
class CustomUserChangeForm(UserChangeForm):
class Meta:
model = CustomUser
fields = ('email',)
Step 6: Admin
Tell the admin panel to use these forms by extending from UserAdmin in users/admin.py
admin.py
from django.contrib import admin
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 = ('username', 'email', 'is_active',
'is_staff', 'is_superuser', 'last_login',)
list_filter = ('is_active', 'is_staff', 'is_superuser')
fieldsets = (
(None, {'fields': ('username', 'email', 'password')}),
('Permissions', {'fields': ('is_staff', 'is_active',
'is_superuser', 'groups', 'user_permissions')}),
('Dates', {'fields': ('last_login', 'date_joined')})
)
add_fieldsets = (
(None, {
'classes': ('wide',),
'fields': ('username', 'email', 'password1', 'password2', 'is_staff', 'is_active')}
),
)
search_fields = ('email',)
ordering = ('email',)
admin.site.register(CustomUser, CustomUserAdmin)
-
add_formandformspecifies the forms to add and change user instances. -
fieldsetsspecifies the fields to be used in editing users andadd_fieldsetsspecifies fields to be used when creating a user.
You can now go to the admin panel and add/edit users.
Source code: https://github.com/earthcomfy/jwt-auth
Top comments (5)
Impressive thanks alot for this Hana
thank God i came across your explanation, this has been confusing for a while now, It is the simplicity of your explanation i love most , thanks Hana
Thanks a lot. I have been looking for hours all over the internet. This helped!
I'm happy to hear that
Very simple to follow. Thank you Hana.