Before we get started, have you tried our newPython Code Assistant? It's like having an expert coder at your fingertips. Check it out!
Many online sites can only be accessed if we register into their systems. Luckily,Django can let us build that authentication system for our apps. In this article, we will create a registration page for new users and login and logout pages for existing users.
The main reason for authenticating users is to restrict content. Authentication ensures that only authorized users have access to a system by preventing unauthorized users from accessing and potentially damaging systems, stealing information or causing other issues.
Table of content:
I'll be using Ubuntu in this tutorial, but you can use any environment you want.
We need to set up a virtual environment first. Creating projects in a segregated environment is always a good practice to avoid interfering with other virtual environments or system-installed Python.
We will create a new directory where our app will be stored. Let's call itnew_project.
$ mkdir new_project$ cd new_projectWe will then create a virtual environment in thenew_project. We will use a Python installer pip to installvirtualenv, which is a tool for creating isolated virtual Python environments.
$ pip install virtualenvLet's call our new virtual"venv".
$ virtualenv venvTo activate it:
$ source venv/bin/activate
First, let's make sure that we have Django installed:
$ pip install DjangoWe will then usedjango-admin tool to generate a project folder. Let's call the projectaccounts:
$ django-admin startproject accountsThe basic structure for our project so far looks like this:
├── accounts│ ├── asgi.py│ ├── __init__.py│ ├── settings.py │ ├── urls.py│ └── wsgi.py└── manage.pyThe above files are:
manage.py - a command-line utility that gives various options for interacting with this Django project.settings.py - This file contains all the website settings. Here, you can register applications you create, configure databases, etc.urls.py - This file stores all links to the project. Simply said, this file instructs Django that if a user enters this URL, they should be directed to the specified website or view.Let's now run migrations.Let's change the directory to where themanage.py file is:
$ cd accountsThemakemigrations command looks through all of your available models and creates migrations for any tables that do not yet exist. Themigrate command executes all unapplied migrations against your database, essentially synchronizing your model changes with the database schema. To carry out migrations:
$ python manage.py makemigrations$ python manage.py migrate
We will then run the server:
$ python manage.py runserver
The development server is live athttp://127.0.0.1:8000/. Visit the link to open the server in the browser.

A Django project can have many apps under it. Let's create an app, and call it"account".
$ python manage.py startapp accountThe app structure looks like this:
.├── admin.py├── apps.py├── __init__.py├── migrations│ └── __init__.py├── models.py├── tests.py└── views.pymodels.py file contains the most important fields and behaviors of the data you're storing.admin.py is where you register the models in your app with the Django admin application.views.py file contains Python functions that take HTTP requests and return HTTP responses, like HTML documents.We then configure the app by including it in theINSTALLED_APPS list insettings.py.
INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'account' # our account app]Django lets us perform create, read, update and delete operations on the models directly through its admin interface. To access the interface, we have to create a user who can log in to the admin site, called a superuser:
$ python manage.py createsuperuserFollow the prompts asked, and create a superuser:

To access the admin site, enter http://127.0.0.1:8000/admin in the browser. Input username and password and log in:

So far, we have one user:

We will create a folder calledTemplates in the root directory:
.├── db.sqlite3├── manage.py├── accounts├── Templates└── accountThis will hold our HTML, CSS, and Javascript files.We configuresettings.py to include ourTemplates folder:
TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': [BASE_DIR/'Templates'], #here 'APP_DIRS': True, 'OPTIONS': { 'context_processors': [ 'django.template.context_processors.debug', 'django.template.context_processors.request', 'django.contrib.auth.context_processors.auth', 'django.contrib.messages.context_processors.messages', ], }, },]Let's create a simple homepage where users will be redirected when they log in. We will usethe Bootstrap framework, which is the most popular CSS framework for creating responsive and mobile-first websites.
We will create a simple template. In theTemplates folder, create a new file calledhome.html:
<!doctype html><html lang="en"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>Bootstrap demo</title> </head> <body> <h1>Hello, world!</h1> </body></html>We then create views of the homepage. A view function, abbreviated as view, is a Python function that accepts a web request and returns a web response. Inviews.py,
from django.shortcuts import render# Create your views here.def home(request): return render(request,'home.html')Every Internet page requires its URL. This way, your application knows what to display to a user who visits that URL.URLconf is a concept used in Django (URL configuration) that is a collection of patterns that Django will try to match with the requested URL to find the correct view.
Inurls.py, add the following code:
from django.contrib import adminfrom django.urls import pathfrom account import views #hereurlpatterns = [ path('admin/', admin.site.urls), path('home/', views.home, name='home'), #here]Great, we have a homepage.Running the server:

We should then create a template that can be inherited by other templates. Let's call itbase.html:
<!doctype html><html lang="en"> <head> <!-- Required meta tags --> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <!-- Bootstrap CSS --> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous"> <title>{% block title %} Simple site {% endblock %}</title> </head> <body> {% block body %} <header class = "header fixed-top"> <nav> <div> <button type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="true" aria-label="Toggle navigation"> <span></span> </button> <div> {% if user.is_authenticated %} <ul> <li> <li> <a href="#" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">{{user.username}}</a> </li> <li> <ahref="#">Log out<span></span></a> </li> </ul> </div> </div> {% else %} <button type="button" data-toggle="collapse" data-target="#mainMenu" aria-controls="mainMenu" aria-expanded="false" aria-haspopup="true" aria-label="Toggle navigation"> <span></span> </button> <form > <a href="#" color="white">Log in</a> <a href="#" class = "btn btn-primary ml-3">Sign up</a> </form> {% endif %} </nav></header> <div> {% block content %}{% endblock %} </div> {% endblock body %} <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM" crossorigin="anonymous"></script> </body></html>We want our site to have a navbar. The navbar should have alog-out button if a user is authenticated (logged in). Their name will be displayed on another button, next to thelog-out button. However, if a user has not yet logged in, then they can access two buttons,signup, and loginbuttons.
A block is used to override specific template elements. This means that a content block is overridden by children who inherit from this template. This can be accomplished by using theextends keyword in child templates. Everything inside{% block body %} and{% endblock body %} will appear in all the templates that will inherit the base template.
We should then extend the contents of the base template to other templates by using the{% block content %} attribute.
Let's rewritehome.html to inherit the base template:
{% extends 'base.html'%}{% block content%}<div> <h3>Hello {{user}}</h3> <h2>This is a simple site </h2></div>{% endblock %}
Since we are the superuser and we have logged in in the admin interface, it has our username displayed.
Let's now create a simple landing page that will be accessed by everybody.In theTemplates folder, create a new file namedlanding_page.html:
{% extends 'base.html'%}{% block content%}<div> <section > <div> <div> <div style = "height:120px;"> </div> <div > <h1 ><b>This is login and sign up landing page test!</b></h1> <h4 >Let's try </h4> <div > <div> <a href="#"> <a href="#" >Get Started</a> <a href="#" >Log in</a> </a> </div> </div> </div> </div> </div> </section> <!-- Footer--> <footer> <div><p>Copyright © Me 2022</p></div> </footer></div>{% endblock%}Let's create its views next. Inviews.py:
def landing_page(request): return render(request,'landing_page.html')We then link the views to the URLs. Inurls.py:
path('', views.landing_page, name='landing_page'),Our landing page looks like this:

Let's now make a signup page that lets users enter their details. First, let's create its view:
from django.shortcuts import render, redirect #add redirectfrom django.contrib.auth import loginfrom django.contrib.auth.forms import UserCreationFormdef signup(request): if request.method == 'POST': form = UserCreationForm(request.POST) if form.is_valid(): user = form.save() login(request, user) return redirect('home') else: form = UserCreationForm() return render(request, 'signup.html', {'form': form})Django includes a user authentication system. To handle the creation of new users, it provides a form calledUserCreationForm (which inherits from theModelForm class). It contains three fields:username,password1, andpassword2 (for password confirmation). To useUserCreationForm, we first import it fromdjango.contrib.auth.forms.
login() uses Django's session framework to save the user's ID in the session. The form should redirect us to the home page using theredirect() function if the form is valid.
Inurls.py, we add a path to signup views:
path('signup/', views.signup, name='signup'),InTemplates folder, we create a new file,signup.html:
{% extends 'base.html' %}{% block content %}<div> <h2>Sign up</h2> <form method="post"> {% csrf_token %} {% for field in form %} <p> {{ field.label_tag }}<br> {{ field }} {% if field.help_text %} <small>{{ field.help_text }}</small> {% endif %} {% for error in field.errors %} <p>{{ error }} {% endfor %} </p> {% endfor %} <button type="submit">Create an account</button> </form></div>{% endblock %}We render the form in the template by iterating through it. We use {% csrf_token %} tag to avoid malicious attacks. When rendering the page, it generates a token on the server and ensures that it is cross-checked for subsequent requests. If the incoming requests lack the token, they are simply not processed.
If there is an error in any field, it will highlight an error message in red color. We then add asubmit button to create a new account:

After filling out the details, it redirects us to the homepage, with our new name updated. To confirm the signed users, let's access the admin interface.

Let's now link theget started button to the signup form onlanding_page.html:
<a href="{% url 'signup' %}" >Get Started</a>By clicking on theget startedbutton, it will direct us to the signup form.
Now that we have setup the signup form let's create a page for the signed-up users to log in.Inviews.py:
from django.contrib.auth.forms import UserCreationForm, AuthenticationForm #Add AuthenticationFormdef log_in(request): if request.method == "POST": form = AuthenticationForm(data=request.POST) if form.is_valid(): user = form.get_user() login(request,user) return redirect('home') else: form = AuthenticationForm() return render(request,'login.html', {"form":form})Django lets us use its built-in form for handling login,AuthenticateForm. If the form is valid, it gets the user whose input data corresponds to existing users.
Inurls.py, add the following:
path('login/', views.log_in, name='login'),We then create a new template in theTemplates folder,login.html:
{% extends 'base.html' %}{% block body %} <div> <h1> <a href="{% url 'home' %}">Simple site</a> </h1> <div> <div> <div> <div> <h3>Log in</h3> <form method="post" novalidate> {% csrf_token %} {{ form.as_p }} <button type="submit">Log in</button> </form> </div> <div> New to Simple site? <a href="{% url 'signup' %}">Sign up</a> </div> </div> </div> </div> </div>{% endblock %}Here, we make sure thatcsrf_token is taken care of. We render the form for logging in. Let's update thelanding_page.html template:
<a href="{% url 'login'%}" >Log in</a>Back to thelog-in button on the landing page; it takes us to the login page:

After the login, we're redirected to the home page:

A user should be able to log out anytime. Inviews.py:
from django.contrib.auth import login, logoutdef log_out(request): logout(request) return redirect('landing_page')Thelogout() function from Django removes the authenticated user's ID from the request and flushes their session data.
Note that we cannot name our functionlogout() as it will conflict with built-in Django functions.Inurls.py, add the following:
path('logout/', views.log_out, name='logout'),We should now link the paths to the navbar buttons for easy accessibility,base.html:
<ahref="{% url 'logout'%}">Log out<span></span></a> <form > <a href="{% url 'login'%}" color="white">Log in</a> <a href="{% url 'signup'%}" class = "btn btn-primary ml-3">Sign up</a> </form>Great. We can now access them by using the navbar buttons. When we click on thelog-out button, it redirects us to the landing page, where we have to either log in or sign up again to access the homepage.
Congratulations! You have successfully created an authentication system in the Django framework! As you already saw, Django offers us convenient tools for the authentication process, with functions likelogin(), andlogout(), and also with pre-built forms such asUserCreationForm andAuthenticateForm.
To get the complete project code, refer tothis link.
For more information about authentication using Django, I invite you to checkDjango's official documentation.
Learn also: How to Build a CRUD Application using Django in Python.
Happy coding ♥
Want to code smarter? OurPython Code Assistant is waiting to help you. Try it now!
View Full Code Build My Python CodeGot a coding query or need some guidance before you comment? Check out thisPython Code Assistant for expert advice and handy tips. It's like having a coding tutor right in your fingertips!
