We created a real estate application using the Django web framework. In the project, we populated our database with information about properties available for sale. We also created a form to quickly add more listings if we don’t want to use the admin panel.
In this tutorial, we will add a registration, login, and logout functionality to the real estate application so that only registered individuals can make inquiries. You will benefit greatly if you go through the previous project first before attempting this one.
User Registration
The advantage of using Django over other web frameworks is that certain features are already inbuilt. User authentication is not an exception. No need to reinvent the wheel. All we have to do is to select and configure it to our needs. To create the registration form, we will import the UserCreationForm
class in our forms.py
file.
from django import forms from django.contrib.auth.models import User from django.contrib.auth.forms import UserCreationForm class RegisterForm(UserCreationForm): email = forms.EmailField(required=True) class Meta: model = User fields = ('username', 'email', 'password1', 'password2') def save(self, commit=True): user = super(RegisterForm, self).save(commit=False) user.email = self.cleaned_data['email'] if commit: user.save() return user
We create a RegisterForm
class that inherits from the UserCreationForm
, and add a required field, EmailField
to the form. The Meta
class is used to change the behavior of a model. In it, we specify that the User
model will be used plus the fields we want to be displayed on the form. The second password field is for confirmation.
The save()
method is used to override the default behavior of the UserCreationForm
class. It first uses the super()
method to call the parent class’ save
method with commit=False
. This creates a new user object without saving it to the database because it hasn’t received the user’s email attribute. Once received, the user object can then be saved to the database.
But you may wonder, what if we do not use the save()
method?
Of course, it will use the parent’s class save
method. However, since the email field is not included in the default field of the UserCreationForm
class, the save()
method ensures that the email is saved along with the other data.
The views for this form will be:
from django.contrib import messages from django.shortcuts import render, redirect from .forms import RegisterForm def register(request): if request.method == 'POST': form = RegisterForm(request.POST) if form.is_valid(): form.save() messages.success(request, 'Your account has been created successfully!') return redirect(‘login’) else: form = RegisterForm() return render(request, 'register.html', {'form': form})
If the request method is POST, the form has been submitted. If the form is valid, it creates a new user, displays a success message and redirects to the login page. Otherwise, it creates a new instance of the RegisterForm
and passes the form as context in the register.html
template.
The URL route will be like this:
path('register', register, name='register'),
For the templates:
{% extends "base.html" %} {% block content %} {% load tailwind_filters %} <!--Register--> <div class="container py-5"> <h1>Register</h1> <form method="POST"> {% csrf_token %} {{ form|crispy }} <button class="btn btn-primary" type="submit">Register</button> </form> {% if messages %} <ul class="messages"> {% for message in messages %} <li{% if message.tags %} class="{{ message.tags }}"{% endif %}>{{ message }}</li> {% endfor %} </ul> {% endif %} <p class="text-center">If you already have an account, <a href="{% url 'login' %}">login</a> instead.</p> </div> {% endblock %}
The form is loaded using crispy tailwind. You can check the source code for more details. If there are messages stored in the message
variable, it will also be displayed automatically.
User Login
Let us create the login page where users will be redirected after a successful registration.
from django.contrib.auth.forms import AuthenticationForm from django.contrib.auth import login, authenticate def login_view(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("contact") else: messages.error(request,"Invalid username or password.") form = AuthenticationForm() return render(request, 'login.html', {"form": form})
We import the AuthenticationForm
class and create an instance of it with the request data if the request method is POST. If the form is valid, the view
function gets the username and the password. It then uses the authenticate()
method to check if the user exists.
If so, it logs the user in using the login()
method and redirects to the contact form. Otherwise, it displays an error message. However, if the request method is not POST, it simply displays an empty form.
For this project, we want the contact page to be assessed only by a registered user. That’s why we are redirecting to the contact page. More on this shortly.
The URL route will be like this:
path('login', login, name='login'),
Be sure to import all the functions for the URLs. For the templates, it will be:
{% extends 'base.html' %} {% load tailwind_filters %} {% block content %} <h2>Login</h2> {% if messages %} <ul class="messages"> {% for message in messages %} <li{% if message.tags %} class="{{ message.tags }}"{% endif %}>{{ message }}</li> {% endfor %} </ul> {% endif %} <form method="post"> {% csrf_token %} {{ form | crispy }} <button type="submit">Login</button> </form> {% endblock %}
Logout
The view
function for logging out is quite simple.
from django.contrib.auth import logout as auth_logout def logout(request): if request.method == 'POST': auth_logout(request) messages.info(request, "You have successfully logged out.") return redirect("home") return render(request, 'logout.html')
The logout()
method ensures the user is successfully logged out. A confirmation message is displayed and the user is redirected to the home page.
Here is the template:
{% extends 'base.html' %} {% block content %} <h1 style="text-align:center">Logout</h1> <p>Are you sure you want to log out?</p> <form method="post"> {% csrf_token %} <button type="submit">Yes</button> </form> {% endblock %}
And the URL:
path('logout', logout, name='logout'),
We have authenticated the application. Users who want to benefit more from our services will be required to register on our platform. Notice how we renamed both our login view and logout()
function to avoid name conflict in the application.
Conclusion
We are done with adding an authentication feature to the real estate application. I have demonstrated how I created a contact form that will only be displayed to users if they are authenticated. Check my GitHub page for the full code as well as some changes I made to the application.
Notice that there is no option to recover your password if lost. Well, that’s not within the scope of this project tutorial.
This simple demonstration will serve as a blueprint, so to speak, if you want to extend this application further with more advanced features.
🤠 Recommended: How I Built a Real Estate Application Using the Django Web Framework