blog image

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

  1. AbstractUser
  2. 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'

About author

author image

Amrit Panta

Python developer, content writer



3 Comments

Amanda Martines 5 days ago

Exercitation photo booth stumptown tote bag Banksy, elit small batch freegan sed. Craft beer elit seitan exercitation, photo booth et 8-bit kale chips proident chillwave deep v laborum. Aliquip veniam delectus, Marfa eiusmod Pinterest in do umami readymade swag. Selfies iPhone Kickstarter, drinking vinegar jean.

Reply

Baltej Singh 5 days ago

Drinking vinegar stumptown yr pop-up artisan sunt. Deep v cliche lomo biodiesel Neutra selfies. Shorts fixie consequat flexitarian four loko tempor duis single-origin coffee. Banksy, elit small.

Reply

Marie Johnson 5 days ago

Kickstarter seitan retro. Drinking vinegar stumptown yr pop-up artisan sunt. Deep v cliche lomo biodiesel Neutra selfies. Shorts fixie consequat flexitarian four loko tempor duis single-origin coffee. Banksy, elit small.

Reply

Leave a Reply

Scroll to Top