How To Create A Custom User Model In Django.

How To Create A Custom User Model In Django.

Introduction.

MVC frameworks like Django brought fresh air and ease to the web development tasks. Time taken to develop complex web application have now been beaten down by the advent of these MVC frameworks like Python/Django.

Even startups like Instagram, Quora and Disqus have a lot to say about the speed that they were able to achieve when developing their platform with Django during their startup days, It took just two weeks to develop what we now call Instagram that powers over 2 Billion people all over the world.

Django has proven to be a dependent and multipurpose framework since development, and I must say that it is one that every aspiring full-stack web developer should try out. Do you want to develop rich applications faster? You should try out Django.

The Main Issue.

When I started developing with Django in my early days, I found out that some things just seem to be rigid about the Django framework, and one of those was how users were being handled.

You have to make use of a username and a password to authenticate users. But what if you wanted to design it your own way, like using an Email instead of a username.

Though it was not rigid as I thought, it seems so because I was just a newbie back then, so I decided to Google it just as you are doing right now, and guess what, I found the solution.

How To Create A Custom User Model In Django.

In this section, we are going to be creating a custom user model in Django in these few steps.

  1. Make sure that your Django project is set up as described in the article here. Activate your virtual environment and navigate to your project root folder.
    Create an accounting app to handle your users.

Python manage.py startapp account
  1. Add it to the installed app section in your project settings.py file.

#my_project/settings.py
INSTALLED_APP = [

    'account'
    #Other Apps

]
  1. Configure your project to work with the newly installed account app by adding this global variable in the settings file of your project.
#my_project/settings.py
AUTH_USER_MODEL = "account.user"

Mind you that you have not created the user model yet, and we will be doing that in a jiffy.

  1. Go to the account app and copy and paste this code in the model section.
#Import this on top

from django.db import models

from django.contrib.auth.models import (
        BaseUserManager,
        AbstractBaseUser

        )

Create a Base User manager, don't worry all you need is copy this code below.

# Add this section still in the models.py 

class UserManager(BaseUserManager):
    def create_user(self, email, full_name,   password=None):
        """
        Creates and saves a User with the given email, date of
        birth and password.
        """
        if not email:
            raise ValueError('Users must have an email address')

        user = self.model(
            email=self.normalize_email(email),
             full_name = full_name,

                   ) 

        user.set_password(password)
        user.save(using=self._db)
        return user

    def create_superuser(self, email, full_name,  password ):

        """
        Creates and saves a superuser with the given email, date of
        birth and password.
        """
        user = self.create_user(
                email,
                full_name = full_name,
                password=password,
                        )


        user.is_admin = True
        user.save(using=self._db)
        return user

Followed by that, now its time to create your user model to suit your personal use. Note that you can tweak this section to suit your own purpose.

class User (AbstractBaseUser):

    full_name         =     models.CharField(max_length = 3000, blank = True, null = True)

    email            =    models.EmailField(verbose_name = 'email address', max_length = 225, unique = True)







    is_active        =    models.BooleanField(default = True)
    is_admin         =    models.BooleanField(default = False)
    objects         =   UserManager()

    USERNAME_FIELD = 'email'
    EMAIL_FIELD = "email"
    REQUIRED_FIELDS = ['full_name' ]




    def __str__(self):
        return str(self.full_name)

    def has_perm (self, perm, obj = None):
        # "Does the user have a specific permission?"
        # Simplest possible answer: Yes, always
        return True

    def has_module_perms(self, app_label):
        # Does the user have permissions to view the app `app_label`?"
        # Simplest possible answer: Yes, always

        return True

    @property     
    def is_staff(self):

        # Is the user a member of staff?"
        # Simplest possible answer: All admins are staff
        return self.is_admin

Bringing all together, we have this in the models.py file of our account app model.


#my_project/account/models.py


from django.db import models

from django.contrib.auth.models import (
        BaseUserManager,
        AbstractBaseUser

        )






class UserManager(BaseUserManager):
    def create_user(self, email, full_name,   password=None):
        """
        Creates and saves a User with the given email, date of
        birth and password.
        """
        if not email:
            raise ValueError('Users must have an email address')

        user = self.model(
            email=self.normalize_email(email),
             full_name = full_name,

                   ) 

        user.set_password(password)
        user.save(using=self._db)
        return user

    def create_superuser(self, email, full_name,  password ):

        """
        Creates and saves a superuser with the given email, date of
        birth and password.
        """
        user = self.create_user(
                email,
                full_name = full_name,
                password=password,
                        )


        user.is_admin = True
        user.save(using=self._db)
        return user


# ACCOUNT_TYPE = (

#     ('IND', 'personal'),
#     ('BUS', 'Business')

#     )



class User (AbstractBaseUser):

    full_name         =     models.CharField(max_length = 3000, blank = True, null = True)

    email            =    models.EmailField(verbose_name = 'email address', max_length = 225, unique = True)







    is_active        =    models.BooleanField(default = True)
    is_admin         =    models.BooleanField(default = False)
    objects         =   UserManager()

    USERNAME_FIELD = 'email'
    EMAIL_FIELD = "email"
    REQUIRED_FIELDS = ['full_name' ]


    def __str__(self):
        return str(self.full_name)

    def has_perm (self, perm, obj = None):
        # "Does the user have a specific permission?"
        # Simplest possible answer: Yes, always
        return True

    def has_module_perms(self, app_label):
        # Does the user have permissions to view the app `app_label`?"
        # Simplest possible answer: Yes, always

        return True

    @property     
    def is_staff(self):

        # Is the user a member of staff?"
        # Simplest possible answer: All admins are staff
        return self.is_admin
  1. Now That that you are done, copy this code and paste it in the admin.py section of the accounts app.
#my_project/account/admin.py

from django import forms
from django.contrib import admin
from django.contrib.auth.models import Group
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
from django.contrib.auth.forms import ReadOnlyPasswordHashField


from account.models import User
# Register your models here.







class UserCreationForm(forms.ModelForm):
    """A form for creating new users. Includes all the required
    fields, plus a repeated password."""
    password1 = forms.CharField(label='Password', widget=forms.PasswordInput)
    password2 = forms.CharField(label='Password confirmation', widget=forms.PasswordInput)

    class Meta:
        model = User
        # fields = ('email', 'first_name', 'last_name')
        fields = ('email', 'full_name')

    def clean_password2(self):
        # Check that the two password entries match
        password1 = self.cleaned_data.get("password1")
        password2 = self.cleaned_data.get("password2")
        if password1 and password2 and password1 != password2:
            raise forms.ValidationError("Passwords don't match, please try another password")
        return password2

    def save(self, commit=True):
        # Save the provided password in hashed format
        user = super().save(commit=False)
        user.set_password(self.cleaned_data["password1"])
        if commit:
            user.save()
        return user


class UserChangeForm(forms.ModelForm):
    """A form for updating users. Includes all the fields on
    the user, but replaces the password field with admin's
    password hash display field.
    """
    password = ReadOnlyPasswordHashField()

    class Meta:
        model = User
        fields = ('full_name', 'email','password', 'is_active', 'is_admin')
        # fields = ('first_name','last_name', 'email','password', 'is_active', 'is_admin')

    def clean_password(self):
        # Regardless of what the user provides, return the initial value.
        # This is done here, rather than on the field, because the
        # field does not have access to the initial value
        return self.initial["password"]


class UserAdmin(BaseUserAdmin):
    # The forms to add and change user instances
    form = UserChangeForm
    add_form = UserCreationForm

    # The fields to be used in displaying the User model.
    # These override the definitions on the base UserAdmin
    # that reference specific fields on auth.User.


    # list_display = ('first_name','last_name','email', 'is_admin','verified')
    list_display = ('full_name','email', 'is_admin',)

    list_filter = ('is_admin', )
    fieldsets = (
        (None, {'fields': ('full_name', 'email', 'password')}),
        ('Personal info', {'fields': ()}),
        ('Permissions', {'fields': ('is_admin',)}),
    )




    # add_fieldsets is not a standard ModelAdmin attribute. UserAdmin
    # overrides get_fieldsets to use this attribute when creating a user.
    add_fieldsets = (
        (None, {
            'classes': ('wide',),
            'fields': ('full_name', 'email', 'password1', 'password2')}
        ),
    )
    search_fields = ('email',)
    ordering = ('email',)
    filter_horizontal = ()




# Now register the new UserAdmin...
admin.site.register(User, UserAdmin)
# ... and, since we're not using Django's built-in permissions,
# unregister the Group model from admin.
admin.site.unregister(Group)
  1. Run migration and sync with the database.
Python manage.py makemigrations
#Then run the code below
Python manage.py migrate.

Conclusion.

That should be all, all you need do is try to create a superuser and login to the admin section of your project.

#create super user from your terminal

python manage.py createsuperuser
# run the local server and visit the admin localhost:8080/admin
Python manage.py runserver

If you get errors make sure you look at the code above and try as much to reconfigure any field that does not match your custom user model to match with it. You should be good to go.

Connect With Me On Twitter.

My friend, It a good thing that we are able to connect on this platform to share innovative ideas, in the meantime I am not an Island of knowledge and I also want to hear from you. I would like to connect with you via Twitter