How to Create User Authentication with the Django Framework on Ubuntu 18.04

Brown wooden door with padlock courtesy of iMattSmart on Unsplash.com

Introduction

In this guide, we will create the user authentication feature for a Django web application for users to log in and log out successfully.

With Django, you can create user authentication by implementing Django’s user authentication feature. Django provides some views to handle our authentication process which includes the LoginView to login a user, LogoutView to logout a user, the PasswordChangeView to display a form for the user to change the password and the PasswordChangeDoneView to redirect the user to a confirmation page after a successful password change.

Prerequisites

  • Familiarity with Python syntax
  • Familiarity with Django framework and Django-admin interface
  • You must have created your Django project with superuser privilege so that you will be able to implement the concepts in this tutorial. You can follow how to create a Django app and connect it to a database to create a basic blog app with Django and follow the tutorial on how to enable and connect the Django admin interface to create superuser privilege. If you however have an existing Django project with superuser privilege, you may use it for this tutorial.

Step 1 — Implement the login and logout views

$ cd [project name]

Where the project name in our case is my_django. Then let's create a new app and call it user_account or any other name with the following command:

$ django-admin startapp user_account

Then add the new app to the top of the INSTALLED_APPS list in the settings.py file.

[label /my_django/my_django/settings.py]
INSTALLED_APPS = [
'user_account',
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
]

Let’s sync our database models with the models of the app with the following command:

$ python manage.py migrate

You should see a similar output like the following:

[secondary_label Output]
Operations to perform:
Apply all migrations: admin, auth, contenttypes, 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 auth.0010_alter_group_name_max_length... OK
Applying auth.0011_update_proxy_permissions... OK
Applying sessions.0001_initial... OK

If you have not created a superuser, you need to create one with the following command:

python manage.py createsuperuser

Supply your desired username, email, and password

Django already provides the LoginView to login a user via a form and the LogoutView log out the user as part of the django.contrib.auth module. Therefore, we do not need to create views for the login and logout. We would only need to map URLs to the views and create templates to be displayed for the user. Add paths to the urls.py of the user_account app as follows:

[label /my_django/user_account/urls.py]
from django.urls import path
from django.contrib.auth import views as auth_views

urlpatterns = [
path('login/', auth_views.LoginView.as_view(), name='login'),
path('logout/', auth_views.LogoutView.as_view(), name='logout'),
]

Then, in the main urls.py file of the my_django project, let us include the URL patterns of the user_account application while importing include:

[label /my_django/my_django/urls.py]
from django.urls import path, include
from django.contrib import admin

urlpatterns = [
path('admin/', admin.site.urls),
path('user_account/', include('user_account.urls')),
]

Step 2 — Create Templates to Render the Views

Django expects your authentication templates to be in a folder named registration. Create a directory templates inside the user_account app and create new files and folders in it as follows:

templates/
| registration/
| | login.html
| | logout.html
| user_account/
| |
|_main.html

Let us make the base template in main.html as follows, following HTML5 convention.

[label /my_django/user_account/templates/main.html]
{% load staticfiles %}
<!DOCTYPE html>
<html>
<head>
<title>{% block title %}My Django{% endblock %}</title>
<link href="{% static "css/main.css" %}" rel="stylesheet">
</head>
<body>
<div class="header" id="header">
<span class="">My Django Website</span>
</div>
<div class="content" id="content">
{% block content %}

{% endblock %}
</div>
</body>
</html>

We can style our templates with Cascading Style Sheets (CSS), that is why we started main.html with the line {% load staticfiles %} in order to access the static files for our app. So, create another directory under the user_account directory and name it static. Then, create a new main.css file inside it as follows:

static/
|_main.css

Add the following CSS codes into the main.css file and save it.

[label /my_django/user_account/static/main.css]

body {
font-family: 'Ubuntu', 'Monteserrat', sans-serif;
font-weight:normal;
margin: 0;
}

.header {
background-color: #01314d;
color: #ffffff;
font-family: Monteserrat, Ubuntu;
padding:10px 100px;
font-size:42px;
overflow:auto;
display: flex;
justify-content: center;
}

.content-body {
display: flex;
justify-content: center;
}

.user {
display: flex;
justify-content: center;
}

form {
overflow:auto;
}

.form-intro {
display: flex;
justify-content: center;
font-weight: lighter;
font-style: italic;
}

.home-intro {
color: #2d6102;
font-style: italic;
background-color: #ecc208;
display: flex;
justify-content: center;
font-weight: lighter;
margin: 0;
border: 0;
padding: 3%;
}

.welcome-text {
display: flex;
justify-content: center;
}

form p {
width:100%;
overflow:auto;
display: flex;
justify-content: center;
display: flex;
justify-content: center;
}

label {
float:left;
clear:both;
color:#333333;
margin-top:1.5%;
margin-bottom:4px;
font-size: 20px;
}

input[type=text], select {
float: left;
width: 25%;
padding: 12px 20px;
margin: 8px 0;
display: inline-block;
border: 1px solid #ccc;
border-radius: 4px;
box-sizing: border-box;
}

input[type=password], select {
float: left;
width: 25%;
padding: 12px 20px;
margin: 8px 0;
display: inline-block;
border: 1px solid #cccccc;
border-radius: 4px;
box-sizing: border-box;
}

input[type=submit] {
float: left;
background-color: #4caf50;
border: none;
color: #ffffff;
padding: 16px 10%;
text-decoration: none;
margin: 4px 2px;
cursor: pointer;
border-radius: 40px;
}

Let us advance further in creating the templates for the LoginView view.

[label /my_django/user_account/templates/user_account/login.html]
{% extends "main.html" %}

{% block title %}Login Page{% endblock %}

{% block content %}
<h1 class="form-intro">Log-in</h1>
<p class="form-intro">Please, use the following form to log-in:</p>
<hr>

<div class="login-form">
<form action="{% url 'login' %}" method="post">
{{ form.as_p }}
{% csrf_token %}
<input type="hidden" name="next" value="{{ next }}" />
<p><input type="submit" value="Log-in"></p>
</form>
</div>
{% endblock %}

The login.html template extends the base template main.html. Then, it checks whether the user input is correct. The input tag with type hidden has a value next to enable the LoginView view to redirect the user to the next app page after successful login. The next parameter is set to a URL in the LoginView. But, we will supply the redirect URL in the settings.py file of the my_django project later in this tutorial.

Let’s create a new logged_out.html template for the users to see when they log out:

[label /my_django/user_account/templates/logged_out.html]
{% extends "main.html" %}

{% block title %}Log-out Page{% endblock %}

{% block content %}
<h1>you are logged out</h1>
<p>You have been logged out. You can however &nbsp<a href="{% url "login" %}">log in again</a>.</p>
{% endblock %}

Step 3 — Implement Login Redirect

from django.contrib.auth.decorators import login_required
from django.shortcuts import render

Then, let us add the homepage view app as follows.

[label /my_django/user_account/views.py]
from django.contrib.auth.decorators import login_required
from django.shortcuts import render

@login_required
def homepage(request):
return render(request, 'user_account/homepage.html')

The @login_required is a decorated that checks whether the user is authenticated so as to display the homepage view, otherwise, the user is directed to the login URL where he can fill the login form. Upon receiving a GET request, the homepage view renders the homepage.html template.

Go to the urls.py file of the user_account application, import views, and create a URL pattern for the homepage view. Make sure to import views. So, the urls.py of the user_account app should look like the following:

from django.contrib.auth import views as auth_views
from django.urls import path
from . import views

urlpatterns = [
path('login/', auth_views.LoginView.as_view(), name='login'),
path('logout/', auth_views.LogoutView.as_view(), name='logout'),
path('homepage/', views.homepage, name='homepage'),
]

We need to add a setting to the settings.py file of our my_django project to tell Django where to redirect to after successful login. Simply add the following line to the settings.py file.

LOGIN_REDIRECT_URL = 'homepage'

Let’s create a template for the homepage view now. Create a new template homepage.html inside the user_account directory under the templates directory of the app. So, the templates directory looks like the following:

templates/
| registration/
| | login.html
| | logout.html
| user_account/
| | homepage.html
|_main.html

Then add the following code to homepage.html:

[label /my_django/user_account/templates/user_account/homepage.html]
{% extends "main.html" %}

{% block title %}Homepage{% endblock %}

{% block content %}
<h1 class="home-intro content-body">Home Page</h1>
<p class="welcome-text">Welcome buddy, have fun.</p>
<div class="content-body">
{% if request.user.is_authenticated %}
If you wish you can &nbsp<a href="{% url "logout" %}"> logout </a>
<!-- &nbsp gives white space in HTML-->
{% endif %}
</div>

{% endblock %}

Go to http://127.0.0.1:8000/admin/on your browser and log in with your superuser credentials which you created earlier on. Then create a user for your app on the dashboard.

Finally, go to http://http://127.0.0.1:8000/user_account/login/ and login as a user.