How to create User Register and Login authentication in Django

In this article, we will learn how to do user registration, login and log out on a site built with Django web framework.

Django is a free and open-source, Python-based web framework that follows the model–template–views architectural pattern. Django advertises itself as “the web framework for perfectionists with deadlines” and “Django makes it easier to build better Web apps more quickly and with less code”.  Django is known for the speed at which you can develop apps without compromising on robustness.

Related content:

# Setting up the project

Ensure that you have python 3 installed. Consult your OS installation guide. I can confirm that it is installed in my machine using this command:

➜ python --version
Python 3.9.13

Before we add the code we need to create have a project. Let us also create a virtualenv that will hold specific version of Python and a set of modules (dependencies) that our application will need.

To create the Virtual environment:

python3 -m pip install virtualenv
python3 -m venv <env-folder>

The virtual environment is now set up. In order to use it, it must be activated in the terminal you want to use it.

To ‘activate’ the virtual environment (any Python version):

source /<path to venv>/bin/activate

This changes your prompt to indicate the virtual environment is active. (<env-folder>) $.

We can now install Django in our virtual env. Use this command to install the latest version of django:

pip install django

Next, we can create a django project. Use this command to create a project. I am calling mine djposts.

django-admin startproject djposts

Finally we will create a Django Application that will has the logic for out user register, login and logout functionality. We will call out application accounts.

Django applications can be used in multiple Django projects.

cd djposts
python manage.py startapp accounts

Now add the app to installed apps in djposts/settings.py:

INSTALLED_APPS = [
    ...
    'accounts',
]

Update the djposts/urls.py file with the following content to include the accounts.urls:

from django.contrib import admin
from django.urls import path, include

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

# Base template

In this guide we will be using a base template for uniform styling accross out site. Save this in templates/base.html.

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>{% block title %}DJ Cart{% endblock %}</title>
  </head>
  <body>
    <header>
      <h1>DJCart</h1>
      <a href="{% url 'core:home' %}">home</a> /
      {% if user.is_authenticated %}
        <a href="{% url 'accounts:logout' %}">logout</a>
      {% else %}
        <a href="{% url 'accounts:login' %}">login</a> / <a href="{% url 'accounts:signup' %}">signup</a>
      {% endif %}
      <hr>
    </header>
    <main>
      {% block content %}
      {% endblock %}
    </main>
  </body>
</html>

Then add the templates directory in settings.py

TEMPLATES = [
    {
        ...
        'DIRS': [os.path.join(BASE_DIR, 'templates')],
        ...
]

# User Registration

Django comes with a built-in user registration form. We just need to configure it to our needs (i.e. collect an email address upon registration). 

First set up the url for registration. We will set up the path /accounts/signup to serve logic from the view signup.

Add these content to djposts/accounts/urls.py.

from django.urls import path

from django.urls import re_path as url
from . import views

app_name = 'accounts'


urlpatterns = [
    url('signup', views.signup, name='signup'),
]

Next let us create out signup view.

Add these content to djposts/accounts/views.py.

from django.contrib.auth import login, authenticate
from django.contrib.auth.forms import UserCreationForm
from django.shortcuts import render, redirect


def signup(request):
    if request.method == 'POST':
        form = UserCreationForm(request.POST)
        if form.is_valid():
            form.save()
            username = form.cleaned_data.get('username')
            raw_password = form.cleaned_data.get('password1')
            user = authenticate(username=username, password=raw_password)
            login(request, user)
            return redirect('home')
    else:
        form = UserCreationForm()
    return render(request, 'signup.html', {'form': form})

Django comes with a pre-built register form called UserCreationForm that connects to the pre-built model User. That is what we are using in this set up. In the logic above, we are registering a user from the POST request parameters and showing a registration form if the request is not POST.

There are two if/else statements within the function. The first checks to see if the form is being posted while the second checks to see if the form is valid. If both are True, then the form information is saved under a user, the user is logged in, and the user is redirected to the homepage showing a success message.

Else, if the form is not valid, an error message is shown. But if the request is not a POST in the first place, meaning the first if statement returned False, render the empty form in the register template. 

Please note that if you wish to add messages to your Django project you must enable the Messages Framework and import messages at the top of views.py

The form is rendered to a template signup.html. Add these content to djposts/accounts/templates/signup.html .

{% extends 'base.html' %}

{% block content %}
  <h2>Sign up</h2>
  <form method="post">
    {% csrf_token %}
    {% for field in form %}
      <p>
        {{ field.label_tag }}<br>
        {{ field }}
        {% if field.help_text %}
          <small style="color: grey">{{ field.help_text }}</small>
        {% endif %}
        {% for error in field.errors %}
          <p style="color: red">{{ error }}</p>
        {% endfor %}
      </p>
    {% endfor %}
    <button type="submit">Sign up</button>
  </form>
{% endblock %}

With the register function complete, you can now go to the register URL, http://127.0.0.1:8000/accounts/signup, in your browser window. Create a testuser account.

If done correctly, you will be redirected to the homepage displaying the success message “Registration successful”.

# User login

Next, let us configure user login. First add a login url to this file djposts/accounts/urls.py.

from django.urls import path

from django.urls import re_path as url
from . import views

app_name = 'accounts'


urlpatterns = [
    url('login', views.user_login, name='login'),
]

The login url uses a user_login view. Let us create it in djposts/accounts/views.py.

from django.contrib.auth import login, authenticate
from django.shortcuts import render, redirect
from django.contrib.auth.forms import AuthenticationForm
from django.contrib import messages


def user_login(request):
	if request.method == "POST":
		form = AuthenticationForm(request, data=request.POST)
		if form.is_valid():
			username = form.cleaned_data.get('username')
			password = form.cleaned_data.get('password')
			user = authenticate(username=username, password=password)
			if user:
				login(request, user)
				messages.info(request, f"You are now logged in as {username}.")
				return redirect("core:dashboard")
			else:
				messages.error(request,"Invalid username or password.")
		else:
			messages.error(request,"Invalid username or password.")
	form = AuthenticationForm()
	return render(request, "login.html", {"form":form})

AuthenticationForm is the pre-built Django form logging in a user. We are importing it from django.contrib.auth.forms at the top of the file.

To write your login function, add an if/else statement that uses the Django function authenticate(). This function is used to verify user credentials (username and password) and return the correct User object stored in the backend.

If the backend authenticated the credentials, the function will run Django login() to log in to the authenticated user. Else if the user is not authenticated, it returns a message to the user stating they entered an invalid username or password. 

The second else statement is if the form is not valid, then it returns a similar error message. 

The final else statement is if the request is not a POST, then return the blank form in the login HTML template in djposts/accounts/templates/login.html

{% extends 'base.html' %}

{% block content %}
  <h2>User Login</h2>
  <form method="post">
    {% csrf_token %}
    {% for field in form %}
      <p>
        {{ field.label_tag }}<br>
        {{ field }}
        {% if field.help_text %}
          <small style="color: grey">{{ field.help_text }}</small>
        {% endif %}
        {% for error in field.errors %}
          <p style="color: red">{{ error }}</p>
        {% endfor %}
      </p>
    {% endfor %}
    <button type="submit">Login</button>
  </form>
  <p class="text-center">Don't have an account? <a href="{% url 'accounts:signup' %}">Create an account</a>.</p>
{% endblock %}

Now go to the login URL, http://127.0.0.1:8000/accounts/login, and log in to your testuser.

You will get the success message and be logged in if you entered the correct username and password.

# User logout

To logout the user, add the logout url to djposts/accounts/urls.py.

from django.urls import path

from django.urls import re_path as url
from . import views

app_name = 'accounts'


urlpatterns = [
    url('logout', views.user_logout, name='logout'),
]

Then create a function user_logout in djposts/accounts/views.py.

from django.contrib.auth import logout
from django.shortcuts import redirect

from django.contrib import messages


def user_logout(request):
	logout(request)
	messages.info(request, "You have successfully logged out.")
	return redirect("core:home")

The&#xA0;logout_request function uses the Django function&#xA0;logout() to log the user out of their account and redirect them to the homepage when the logout URL is requested. 

# Conclusion

In this guide we learnt how to use the built in Django functionality to facilitate user register, login and logout.

comments powered by Disqus
Citizix Ltd
Built with Hugo
Theme Stack designed by Jimmy