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 orsource 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 shouldcd
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, typepython 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 thesettings.py
file so, open up thesettings.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
to:from django.urls import path
from django.urls import path, include
- In the
urlpatterns
list, add the following linepath('auth/', include('authentication.urls')),
- Open the
authentication
directory and create a new file and name iturls.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 thesettings.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 commandpython 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 theauthentication
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 yourEmail
,First Name
,Last Name
andPassword
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 toSuperuser 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:
-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:
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!!