A Guide to User Registration, Login, and Logout in Django

Aug. 12, 2020, 3:28 p.m.

Django · 9 min read

A Guide to User Registration, Login, and Logout in Django

This article will cover how to allow user registration, login, and logout functionality on a site built using the Django Web Framework. 

Before we begin, the virtual environment is called env, the Django project is called mysite, and the app is called main.

 


 

User registration

As you may have seen, 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). 

 

Create the register form

env > mysite > main > (New File) forms.py

from django import forms
from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth.models import User


# Create your forms here.

class NewUserForm(UserCreationForm):
	email = forms.EmailField(required=True)

	class Meta:
		model = User
		fields = ("username", "email", "password1", "password2")

	def save(self, commit=True):
		user = super(NewUserForm, self).save(commit=False)
		user.email = self.cleaned_data['email']
		if commit:
			user.save()
		return user

First, customize the registration form in a new file called forms.py.

Django comes with a pre-built register form called UserCreationForm that connects to the pre-built model User. However, the UserCreationForm only requires a username and password (password1 is the initial password and password2 is the password confirmation).

So call UserCreationForm within a new class called NewUserForm and add another field called email. Then save the email to the user.

This same process can be done with any other fields you wish to add to the UserCreationForm.

 

Create a register.html file

env > mysite > main > templates > main > (New File) register.html

{% extends "main/header.html" %}

{% block content %} 

{% load crispy_forms_tags %}         

<!--Register--> 
<div class="container py-5">
	<h1>Register</h1>
	<form method="POST">
		{% csrf_token %}
		{{ register_form|crispy }}                    
		<button class="btn btn-primary" type="submit">Register</button>
	</form>
	<p class="text-center">If you already have an account, <a href="/login">login</a> instead.</p>
</div>

{% endblock %}

Next,  create an HTML template where the form will render. We will call this template register.html.

The template is built using Bootstrap and Django crispy-forms and also uses the Django extends template tag.

 

Add a register URL to the app

env > mysite > main > urls.py

from django.urls import path
from . import views

app_name = "main"   


urlpatterns = [
    path("", views.homepage, name="homepage"),
    ...
    path("register", views.register_request, name="register")
]

Now add a register path to the app's URLs so we can refer to it in the views.

 

Add a register function to the views

env > mysite > main > views.py

from django.shortcuts import  render, redirect
from .forms import NewUserForm
from django.contrib.auth import login
from django.contrib import messages #import messages

def register_request(request):
	if request.method == "POST":
		form = NewUserForm(request.POST)
		if form.is_valid():
			user = form.save()
			login(request, user)
			messages.success(request, "Registration successful." )
			return redirect("main:homepage")
		messages.error(request, "Unsuccessful registration. Invalid information.")
	form = NewUserForm
	return render (request=request, template_name="main/register.html", context={"register_form":form})

Import NewUserForm from forms.py and login from django.contrib.auth. Then write a new views function called register_request.

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

 

Test the register user functionality

Register form

With the register function complete, you can now go to the register URL, http://127.0.0.1:8000/register, in your browser window.

Create a testuser account.

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

Now let's check for the user information in the Django administration.

 

Create a superuser

Terminal/Command Prompt

(env) C:\Users\Owner\Desktop\Code\env\mysite>py manage.py createsuperuser
Username (leave blank to use 'owner'): owner
Email address: 
Password: *****
Password (again): *****
Superuser created successfully.

(env) C:\Users\Owner\Desktop\Code\env\mysite>py manage.py runserver

If you haven't already, create a superuser account to gain access to the Django administration. We are going to check that the user was properly added to the database.

Run the command py manage.py createsuperuser in Windows Command Prompt and python3 manage.py createsuperuser in Mac Terminal. Then fill out the username and password.

 

Check to see if the user is listed in the Django admin

Go to the http://127.0.0.1:8000/admin/ URL where you will see a Django administration login.

If you are still logged in as the testuser you will get the warning message "You are authenticated as testuser1, but are not authorized to access this page. Would you like to login to a different account?".

Yes, you do.

Login to the admin with your superuser account then click on "Users". There you should see a list of all usernames and emails along with their staff status.

 


 

User login 

Now you may have noticed the views function we created automatically logged a user in upon account creation. Be we want the user to have the ability to login freely. So we need a login template, URL, and views function.

 

Create a login.html file

env > mysite > main > templates > main > (New File) login.html

{% extends "main/header.html" %}

{% block content %}      

{% load crispy_forms_tags %}

<!--Login--> 
<div class="container py-5">
  <h1>Login</h1>
  <form method="POST">
    {% csrf_token %}
    {{ login_form|crispy }}
    <button class="btn btn-primary" type="submit">Login</button>
  </form>
  <p class="text-center">Don't have an account? <a href="/register">Create an account</a>.</p>
</div>

{% endfor %}

The basic structure of the HTML template is similar to the register HTML. The only differences are the form and the link at the bottom.

 

Add a login URL

env > mysite > main > urls.py

from django.urls import path
from . import views

app_name = "main"   


urlpatterns = [
    path("", views.homepage, name="homepage"),
    ...
    path("register", views.register_request, name="register"),
    path("login", views.login_request, name="login")
]

Add a login path to the URLs.

 

Add a login function to the views

env > mysite > main > views.py

from django.shortcuts import  render, redirect
from .forms import NewUserForm
from django.contrib.auth import login, authenticate #add this
from django.contrib import messages
from django.contrib.auth.forms import AuthenticationForm #add this

def register_request(request):
	...

def login_request(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 is not None:
				login(request, user)
				messages.info(request, f"You are now logged in as {username}.")
				return redirect("main:homepage")
			else:
				messages.error(request,"Invalid username or password.")
		else:
			messages.error(request,"Invalid username or password.")
	form = AuthenticationForm()
	return render(request=request, template_name="main/login.html", context={"login_form":form})

Now go back to views.py and add authenticate to the list of imports form django.contrib.auth then import AuthenticationForm from django.contrib.auth.forms at the top of the file.

AuthenticationForm is the pre-built Django form logging in a user.

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. 

 

Test the user login functionality

Login form

Now go to the login URL, http://127.0.0.1:8000/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.

 

BONUS: Allow signups through social media accounts (i.e. Facebook, Google, Twitter ...)

Django allauth

 

As of right now, the login is only available through Django's built-in UserCreationForm but you can easily use django-alluth to quickly handle and create signup flows. This means users can create a user account using their social media accounts. You can follow that tutorial here.

 


 

User logout

The last thing we need to handle is user logout. We will place the logout link in the navbar but it is only seen by the user if they are authenticated (i.e. they are logged in).

<!--Navbar-->
<nav class="navbar navbar-expand-lg navbar-light bg-light">
  <a class="navbar-brand" href="#">Navbar</a>
  <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarText" aria-controls="navbarText" aria-expanded="false" aria-label="Toggle navigation">
    <span class="navbar-toggler-icon"></span>
  </button>
  <div class="collapse navbar-collapse" id="navbarText">
    <ul class="navbar-nav mr-auto">
      {% if user.is_authenticated %}
      
      <li class="nav-item">
        <a class="nav-link" href="/logout">Logout</a>
      </li>
      <li class="nav-item">
        <a class="nav-link" href="#">Welcome, {{user.username}}</a>
      </li>

      {% else %}

      <li class="nav-item">
        <a class="nav-link" href="/login">Login</a>
      </li>

      {% endif %}
    </ul>
  </div>
</nav>

The Django template variable {{ user }} stores the current logged-in user and their permissions are available in the template context.

All we need to do is add an if/else statement that if the user is authenticated show the logout link and their username, else show a login link.

This is a basic navigation bar from the Bootstrap documentation. If you are looking to further customize it, then refer to the article 10 Custom Bootstrap Navbars.

 

Add a logout URL

env > mysite > main > urls.py

from django.urls import path
from . import views

app_name = "main"   


urlpatterns = [
    path("", views.homepage, name="homepage"),
    ...
    path("register", views.register_request, name="register"),
    path("login", views.login_request, name="login"),
    path("logout", views.logout_request, name= "logout"),
]

Now add a logout URL path to the app's URLs.

 

Add a log out function

env > mysite > main > views.py

from django.shortcuts import  render, redirect
from .forms import NewUserForm
from django.contrib.auth import login, authenticate, logout #add this
from django.contrib import messages
from django.contrib.auth.forms import AuthenticationForm

def register_request(request):
	...

def login_request(request):
	...

def logout_request(request):
	logout(request)
	messages.info(request, "You have successfully logged out.") 
	return redirect("main:homepage")

Finally, add a logout function to the views file. The logout_request function uses the Django function logout() to log the user out of their account and redirect them to the homepage when the logout URL is requested. 

 

Test the user logout functionality

User logged in

Go to the browser window and reload the page.

Login back in if you need to.

There should be a navbar with a logout link next to the welcome user text.

 

Logout

 

Click the logout link and the homepage should reload showing the logout message while only displaying a login link.

 

What happens if the user forgets their password?

The last thing to think about are user password resets.

Django also handles this functionality using its authentication system.

If you wish to learn how to allow users the ability to send a reset password to themselves, follow the tutorial Reset User Passwords in Django.

Password reset form

 


 

Django + Bootstrap Login Templates

If you are looking to further customize these register and login forms, checkout 14 Custom User Login Forms

User login forms


0
Subscribe now

Subscribe to stay current on our latest articles and promos





Post a Comment
Join the community

1 Comments


Cognextech Sept. 23, 2020, 3:06 a.m.

The article was absolutely fantastic! Lot of great information which can be helpful in some or the other way. Keep updating the blog, looking forward for more contents. By Cognex(https://www.cognextech.com/aws-training-and-certification-course-3)