Create a custom user model in django-3 with email as the default username field

by Abhishek Vaish
Dec 23, 2020



Note : this needs to be done before applying any migrations to the database as we will be overwriting the default user model in django


create an app if don't have one
    python manage.py createapp user

now in user/models.py we first have to create our custom user model

from django.contrib.auth.models import AbstractBaseUser
from django.db import models
from PIL import Image # this is for profile image

class User(AbstractBaseUser):

    # custom fields  here

    email = models.EmailField(verbose_name='email',max_length=60,unique=True)
    first_name = models.CharField(max_length=50)
    last_name = models.CharField(max_length=50)
    img = models.ImageField(default='default.jpg')


    # these are compulsory fields

    date_joined = models.DateTimeField(verbose_name='date joined', 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 tells django to use email as login field

    USERNAME_FIELD = 'email'


    # you don't need to add email to required field

    REQUIRED_FIELDS = ['first_name','last_name']



    # it specify which manager to use when a user is created

    objects = UserManager()



    def __str__(self):
        return f"User : {self.email}"



    # Compulsory functions
    # For checking permissions. to keep it simple all admin have ALL permissons

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


    # Does this user have permission to view this app? (ALWAYS YES FOR SIMPLICITY)

    def has_module_perms(self, app_label):
        return True



    # overwriting custom save to resize image 

    def save(self,*args,**kwargs):
        super(User,self).save(*args,**kwargs)
        img_reshaped = Image.open(self.img.path)
        img_reshaped =  img_reshaped.resize((225,225))
        img_reshaped.save(self.img.path)

now we also need to add a manager to manage this model whenever a new user is created now in the same models.py add

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

class UserManager(BaseUserManager):
    ''' 
    it is mandatory to overwrite create_user and creat_superuser function 
    '''
    def create_user(self,email,first_name,last_name,password):
        if not email:
            raise ValueError("User must have an email")
        if not first_name:
            raise ValueError("User must have a first name")
        if not last_name:
            raise ValueError("User must have a last name")
        if not password:
            raise ValueError("User must have a password")

        user = self.model(
            email=self.normalize_email(email),
            first_name=first_name,
            last_name=last_name,
        )
        user.set_password(password)
        user.save(using=self._db)
        return user

    def create_superuser(self,email,first_name,last_name,password):
        user = self.create_user(
            email=email,
            first_name=first_name,
            last_name=last_name,
            password=password
        )
        user.is_admin = True
        user.is_staff = True
        user.is_superuser = True
        user.save(using=self._db)
        return user



So the complete user/models.py looks something like

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

class UserManager(BaseUserManager):

    ''' 
    it is mandatory to overwrite create_user and creat_superuser function 
    '''

    def create_user(self,email,first_name,last_name,password):
        if not email:
            raise ValueError("User must have an email")
        if not first_name:
            raise ValueError("User must have a first name")
        if not last_name:
            raise ValueError("User must have a last name")
        if not password:
            raise ValueError("User must have a password")

        user = self.model(
            email=self.normalize_email(email),
            first_name=first_name,
            last_name=last_name,
        )
        user.set_password(password)
        user.save(using=self._db)
        return user

    def create_superuser(self,email,first_name,last_name,password):
        user = self.create_user(
            email=email,
            first_name=first_name,
            last_name=last_name,
            password=password
        )
        user.is_admin = True
        user.is_staff = True
        user.is_superuser = True
        user.save(using=self._db)
        return user



class User(AbstractBaseUser):

    # custom fields  here

    email = models.EmailField(verbose_name='email',max_length=60,unique=True)
    first_name = models.CharField(max_length=50)
    last_name = models.CharField(max_length=50)
    img = models.ImageField(default='default.jpg')



    # these are compulsory fields

    date_joined = models.DateTimeField(verbose_name='date joined', 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 tells django to use email as login field

    USERNAME_FIELD = 'email'


    # you don't need to add email to required field

    REQUIRED_FIELDS = ['first_name','last_name']


    # it specify which manager to use when a user is created

    objects = UserManager()

    def __str__(self):
        return f"User : {self.email}"


    # Compulsory functions

    # For checking permissions. to keep it simple all admin have ALL permissons

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


    # Does this user have permission to view this app? (ALWAYS YES FOR SIMPLICITY)

    def has_module_perms(self, app_label):
        return True


    # overwriting custom save to resize image

    def save(self,*args,**kwargs):
        super(User,self).save(*args,**kwargs)
        img_reshaped = Image.open(self.img.path)
        img_reshaped =  img_reshaped.resize((225,225))
        img_reshaped.save(self.img.path)

Migrate the changes to the database

    python manage.py makemigrations
    python manage.py migrate

testing the model

create a superuser using the shell

    python manage.py createsuperuser

add the user model in admin panel

In user/admin.py

from django.contrib import admin
from .models import User
admin.site.register(User)