Django Ecommerce - Customizing Authentication

Hello, I am Thuha and welcome to django-ecommerce post 2.
If you haven't read the previous post (Setting up the project) that this one follows, click here to skim through and make sure you can follow this one comfortably.
This post will be comprised of two sections.
In the first section, I will take you through the steps you need to take to customise django User class that exists in django.contrib.auth.models to use our own CustomUser that will inherit from the AbstractBaseUser of the django.contrib.auth.models
In the second section, we will create the functionality that enables the user to sign up, login and change password.
In an ecommerce site, it is necessary that the site has this functionality for obvious reasons.

Part 1: Customizing Authentication

Why do we need to create our own CustomUser class? Django has a default User class that is "good enough for most common cases." The default User class takes a username, password and email as the necessary attributes to create a user object. However for our purposes, we need the firstname, lastname, email and password, and we do not need the username field.
The first thing we will do is to create a standalone application that will handle our authentication needs.

The following steps will guide you through.

  • Open up the command prompt and activate the virtual environment we had created and installed the dependencies in the previous blog, by typing Envs\eshop\Scripts\activate on windows or source eshop/bin/activate on ubuntu. If you are following directly from the previous tutorial, you can skip this step. To tell if your virtual environment is activated it should have parenthesis and be similar to this:
    (eshop) C:\Users\Thuha\Desktop\eshop>
    Note that the second part(C:\Users\Thuha\Desktop\eshop) is the path to my root eshop project directory so incase you are not in your root project directory, you should cd into that directory by simply typing
    cd the\\path\\to\\your\\root\\directory

  • The next step is to create a new app - in django terms. We will simply name this application "authentication".
    On the command line, type python manage.py startapp authentication

  • By looking at the directory structure now, you should have a new folder named authentication with six files(__init__.py, admin.py, apps.py, models.py, views.py) and two folders(__pycache__, migrations)

The directory structure should therefore look like this:

eshop/
|- manage.py
|-authentication/
   | - __init__.py---------------- #Empty file to enable python to read this folder as a package
   | - admin.py----------------#Admin configurations file
   | - apps.py
   | - models.py----------------#Where we will write our model classes
   | - views.py----------------#Where we will place our views
   | -__pycache__
   | - migrations----------------#Where the migrations file are put
|- eshop/
  | - urls.py---------------- # urls configuration file
  | - settings.py---------------- # Website configuration file
  | - __init__.py---------------- # Empty file to enable python to read this folder as a package
  | - wsgi.py
  | - asgi.py


All the additional apps directories will look like this. We might add some new files but this is the basic structure.

  • The next step is to add the authentication app to the INSTALLED_APPS setting in the settings.py file so, open up the settings.py file and add the following as the last item in theINSTALLED_APPS list:
    'authentication.apps.AuthenticationConfig',
    
  • The full section should now look like this:
    INSTALLED_APPS = [
      'django.contrib.admin',
      'django.contrib.auth',
      'django.contrib.contenttypes',
      'django.contrib.sessions',
      'django.contrib.messages',
      'django.contrib.staticfiles',
      'authentication.apps.AuthenticationConfig',
    ]
    
  • open up the urls.py in the same directory and change the line
    from django.urls import path
    
    to:
    from django.urls import path, include
    
  • In the urlpatterns list, add the following line
    path('auth/', include('authentication.urls')),
    
  • Open the authentication directory and create a new file and name it urls.py
  • In this directory add the following code:
from django.urls import path
urlpatterns = [
]
  • This new urlpatterns list is where we will configure our urls
  • Now we need to customise the User. We will create two classes, one which is the Manager class and the second one is the CustomUser class.
  • Open the models.py file and fill it with the following code.
from django.db import models
from django.contrib.auth.models import AbstractBaseUser, BaseUserManager



class CustomUserManager(BaseUserManager):
    '''
    Custom user manager
    '''

    def create_user(self, email, password, first_name, last_name):
        '''
        This method creates and saves a user with the given email, password, firstname and lastname
        '''

        # Check if the email is provided. If not, raise an error
        if not email:
            raise ValueError('Users must have an email address')

        email = self.normalize_email(email)
        user = self.model(
            email=email, 
            first_name=first_name, 
            last_name=last_name,
            password=password)
        user.set_password(password)
        # save the user to the default database
        user.save(using=self._db)
        return user

    def create_superuser(self, email, password, first_name, last_name):
        '''
        Create a superuser with the given email, password, firstname, lastname
        '''
        user = self.create_user(
            email=email, 
            password=password,
            first_name=first_name, 
            last_name=last_name
            )
        # Since the user is a superuser the following should be set
        user.is_active = True
        user.is_admin = True
        # save the superuser to the default database
        user.save(using=self._db)
        return user
  • The code above defines a CustomUserManager that inherits from the BaseUserManager. Before you copy and paste it, go through it carefully to undestand what is does. I have tried to make some simple comments in places where it might be hard to understand
  • Copy the code below and paste it in the models.py file below the code above
class CustomUser(AbstractBaseUser):
    '''
    Custom user class inherits from the AbstractBaseUser. The fields email and password are required
    '''
    first_name = models.CharField(max_length=20)
    last_name = models.CharField(max_length=20)
    email = models.EmailField(unique=True)
    is_active = models.BooleanField(default=True)
    is_admin = models.BooleanField(default=False)


    # Specify the manager for this specific user model
    objects = CustomUserManager()
    USERNAME_FIELD = 'email'
    REQUIRED_FIELDS = ['first_name', 'last_name']

    def __str__(self):
        return self.email


    class Meta:
        verbose_name = "Users"
        verbose_name_plural = "Users"

    @property
    def is_staff(self):
        "Is the user a member of staff?"
        # Simplest possible answer: All admins are staff
        return self.is_admin

    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
  • The code above defines the CustommUser class that we are going to use to authenticate.
  • To ensure that django uses our new created `CustomUser, open up the settings.py file and add the following variable to the file
AUTH_USER_MODEL = 'authentication.CustomUser'
  • Now that we have created our custom user and instructed django to use it to authenticate, we want to be able to access the admin site. However, we haven't yet created the database table that our users are going to be stored in. To do this, open up the command prompt, where we left it, and type the following commands.
    python manage.py makemigrations
    press enter and type the following command
    python manage.py migrate you will see output similar to this one
Operations to perform:
  Apply all migrations: admin, auth, contenttypes, authentication, sessions
Running migrations:
  Applying contenttypes.0001_initial... OK
  Applying auth.0001_initial... OK
  Applying admin.0001_initial... OK
  Applying admin.0002_logentry_remove_auto_add... OK
  Applying admin.0003_logentry_add_action_flag_choices... OK
  Applying contenttypes.0002_remove_content_type_name... OK
  Applying auth.0002_alter_permission_name_max_length... OK
  Applying auth.0003_alter_user_email_max_length... OK
  Applying auth.0004_alter_user_username_opts... OK
  Applying auth.0005_alter_user_last_login_null... OK
  Applying auth.0006_require_contenttypes_0002... OK
  Applying auth.0007_alter_validators_add_error_messages... OK
  Applying auth.0008_alter_user_username_max_length... OK
  Applying auth.0009_alter_user_last_name_max_length... OK
  Applying authentication.0001_initial... OK
  Applying sessions.0001_initial... OK
  • Our user table has been created.

  • Now we need to register our user on the admin page. Open up admin.py file in the authentication folder and add the following code.

from django.contrib import admin
from django.contrib.auth.models import Group
from .models import CustomUser

#Class to display the fields in the admin page
class CustomUsersAdmin(admin.ModelAdmin):
    list_display = ['first_name','last_name','email']

#Register the User model
admin.site.register(CustomUser, CustomUsersAdmin)

#Unregister the Group class
admin.site.unregister(Group)
  • With that, you have registered the CustomUser class on the admin and you are ready to authenticate as an admin.

  • Open the command prompt and type python manage.py createsuperuser
    This command is going to prompt you to enter your Email, First Name, Last Name and Password If you enter an invalid email address, it is going to prompt you to enter a valid one. If you follow the prompts and enter all the required inputs, You should see a message similar to Superuser created successfully.

  • Type in the following command to startup the server
    python manage.py runserver
  • Oen your browser and type in the following address localhost:8000/admin/
  • You will see a prompt to login as follows:

login_prompt.png -Type in the details that you put assigned your superuser.

  • Once hit login, you should have been logged in to your admin site. You screen should be similar to the following:

admin_homepage.png

  • If see this prompt, Congratulations, you have done well. You have customised the User class and you can now follow the next step.

  • If you encountered an error that you cant seem to correct, reach out to me on my email and I will be happy to help.

-Follow for the next part of the tutorial

Thanks. Happy Coding!!