Custom user Model In Django
In this tutorial we will learn custom user model in django.
Custom User Model
Custom User Model allows you to define a new user model with new fields and managers.
SETUP
Before defining User Model first you should create a new app called userauth in your project
python manage.py startapp userauth
SETTINGS
Add your new app in settings.py
INSTALLED_APPS = [
----
'userauth',
]
AUTH_USER_MODEL = 'userauth.CustomUser'
Implementing Custom User Model
When you are using a custom user model. Django provides you two base classes that you can use to extend user model
- AbstractUser
- AbstractBaseUser
AbstractUser
Abstract User class extends existing fields and methods of the default User class.
from django.contrib.auth.models import AbstractUser
class CustomUser(AbstractUser):
pass
You can also define additional fields and method
from django.contrib.auth.models import AbstractUser
from django.db import models
class CustomUser(AbstractUser):
email = models.EmailField(unique=True)
email_verfield = models.BooleanField(default=False)
USERNAME_FIELD = 'email'
EMAIL_FIELD = 'email'
REQUIRED_FIELDS = ['username', ]
USERNAME_FIELD - set this to a field that you want to use with login
EMAIL_FIELD - set to a field that contains user primary email. If not specified default value is 'email'
REQUIRED_FIELDS - list of fields that must be specified when a user is login with 'python manage.py createsuperuser' command
AbstractBaseUser
AbstractBaseUser class extends no existing fields and methods of the default User class. Except password field.
Model Manager
Before creating a custom user model. First, we need to add a custom Manager
Create manager.py file in userauth app
manager.py
from django.contrib.auth.models import BaseUserManager
from django.core.exceptions import ValidationError
class CutomUserManager(BaseUserManager):
def create_user(self, username, email, password=None):
if not username or username is None:
raise ValidationError("User must have username")
# raise TypeError("user should have username")
if not email or email is None:
raise ValidationError("User must have email address")
# raise TypeError("user should have email")
user = self.model(
username=username,
email=self.normalize_email(email),
)
user.set_password(password)
user.save(using=self._db)
return user
def create_superuser(self, username, email, password):
user = self.create_user(username=username,
email=email,
password=password)
user.is_superuser = True
user.is_admin = True
user.is_staff = True
user.save(using=self._db)
return user
Create a custom user class using AbstractBaseUser
models.py
import uuid
from django.db import models
from django.contrib.auth.models import AbstractBaseUser
from django.contrib.auth.models import PermissionsMixin
from userauth.manager import CutomUserManager
class CustomUser(AbstractBaseUser, PermissionsMixin):
uuid = models.UUIDField(
unique=True, default=uuid.uuid4, editable=False
)
email = models.EmailField(max_length=255, unique=True)
username = models.CharField(max_length=50,
unique=True)
first_name = models.CharField(null=True, blank=True, max_length=100)
last_name = models.CharField(null=True, blank=True, max_length=100)
is_verified = models.BooleanField(default=False)
is_active = models.BooleanField(default=True)
is_admin = models.BooleanField(default=True)
is_superuser = models.BooleanField(default=False)
is_staff = models.BooleanField(default=False)
created_by = models.ForeignKey('CustomUser',
null=True, blank=True,
on_delete=models.CASCADE,
related_name="custom_users")
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
USERNAME_FIELD = 'email'
EMAIL_FIELD = 'email'
REQUIRED_FIELDS = ['username', ]
objects = CutomUserManager()
def __str__(self):
return f"{self.id}: {self.email}"
def token(self):
return ""
class Meta:
verbose_name = "User"
verbose_name_plural = "Users"
Admin
Now we are going to show custom user model in admin pannel
Model Form
Model Forms are used when you create a new user from the admin panel. or update password of existing user
Create forms.py file in userauth app
forms.py
from django import forms
from django.contrib.auth.forms import ReadOnlyPasswordHashField
from userauth.models import CustomUser
class CustomUserChangeForm(forms.ModelForm):
password = ReadOnlyPasswordHashField(label=("Password"),
help_text=("Djang does not stores password in readable form, So you cannot see"
" this user's password, but you can change the password "
"using <a href=\"../password/\">this form</a>."))
class Meta:
model = CustomUser
fields = ("email", 'username')
def clean_password(self):
return self.initial['password']
class CustomUserAddForm(forms.ModelForm):
password = forms.CharField(label="Password", widget=forms.PasswordInput)
confirm_password = forms.CharField(label="Confirm Password", widget=forms.PasswordInput)
def clean(self):
super(CustomUserAddForm, self).clean()
password = self.cleaned_data['password']
confirm_password = self.cleaned_data['confirm_password']
if password and confirm_password and password != confirm_password:
raise forms.ValidationError({"password": "Passwords didn't match, Please enter again."})
else:
pass
admin.py
from django.contrib import admin
from userauth.models import CustomUser
from django.contrib.auth.admin import UserAdmin
from userauth.forms import CustomUserAddForm, CustomUserChangeForm
@admin.register(CustomUser)
class CustomUserAdmin(UserAdmin):
add_form = CustomUserAddForm
form = CustomUserChangeForm
list_display = ('id', 'username', 'email')
list_filter = ('is_admin', 'is_active', 'is_superuser', 'is_staff')
readonly_fields = ['created_at', 'updated_at', 'last_login', 'created_by', 'uuid']
search_fields = ('id', 'uuid', 'username', 'email')
ordering = ('id', )
fieldsets = (
('User', {'fields': ('uuid', 'username', 'email', 'password', 'created_by')}),
('Permissions', {'fields': ('is_active', 'is_superuser', 'is_admin', 'is_staff')}),
('Dates', {'fields': ('created_at', 'updated_at', 'last_login',)}),
)
add_fieldsets = (
(None, {
"classes": ("wide",),
"fields": ("email", "username", "password", "confirm_password"),
}),
)
def save_model(self, request, obj, form, change):
if not change:
obj.created_by = request.user
super().save_model(request, obj, form, change)
SETTINGS
Add your new app in settings.py
INSTALLED_APPS = [
----
'userauth',
]
AUTH_USER_MODEL = 'userauth.CustomUser'