How I Added a Captcha in a Django Web Application

You have created a Django website or blog, and have made it open for users to register an account, log in and benefit from the services you offer. Your utmost concern is security. You want to make sure that your website is free from spam.

Also, you want to ensure you are dealing with humans, not robots. Especially important in a world post-GPT. You can do so by adding a captcha.

πŸ€– Captcha is one of the ways to verify the authenticity of users visiting your website. In our previous tutorials, we learned how to perform email verification using an API in a Flask application. You can further increase the security of your website by adding a captcha.

In this tutorial, we will learn how to do just that using the Django framework which removes the difficulties involved and offers a simple way to add a captcha in your web application.

This tutorial creates a Django application from scratch for the benefit of those new to the Python web framework. You may choose to skip this part if you have already set up Django on your system.

For the new ones in our midst, the importance of learning this may not be completely obvious, but you will find this helpful when you create a full-blown website and want to add a layer of extra security to it. If you are already familiar with Django but haven’t learned to add a captcha to your web application, this project article will help you.

Setting up Django

Run the following commands in the order in which they are written to create a new directory, create and activate a virtual environment, and install the libraries we will need in this project.

πŸ’‘ The full code for this project is on my GitHub page.

mkdir django_project && cd django_project
python3 -m venv .venv
source .venv/bin/activate
pip install django tzdata django-simple-captcha
pip freeze > requirements.txt

You will see that during the installation, it will download Pillow as a dependency for django-simple-captcha. Continue working on your terminal to create a Django project.

django-admin startproject project .
python3 manage.py startapp captcha_app

The dot . command means the Django project will be created in the current directory. Otherwise, it will create a folder for the application.

Configurations

It’s time to configure the application in the settings.py file. Let’s first create a templates folder to keep template files.

mkdir templates

Open the settings.py file from the project folder and add the following to the INSTALLED_APP section.

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',

    # custom app
    'captcha_app',

    # third-party app
    'captcha',
]

Notice we added the django-simple-captcha module to the INSTALLED_APP section. This enables Django to use the feature in our application. Next, register the templates folder under the TEMPLATES section.

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [os.path.join(BASE_DIR, 'templates')], #add these
        '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',
            ],
        },
    },
]

Creating Forms

We are not working with a database, as such, no models will be created. But we will be working with forms. If you have been following my Django project tutorials, you will notice that this is my first time working with forms in Django projects.

Django makes life easy for developers with its built-in forms. It removes the difficulty and security concerns that come with accepting input from users and provide a rich set of tools for developers to use while working with forms.

The form we will create for this project is going to be a simple one. Create a forms.py inside the captcha_app folder.

from django import forms
from captcha.fields import CaptchaField

class CaptchaForm(forms.Form):
    captcha = CaptchaField()

We use the CaptchaField that contains the captcha. Once we add it to the template file, we will see the captcha displayed. Of course, you can add other fields to the CaptchaForm class.

Creating views

from django.shortcuts import render
from .forms import CaptchaForm
from django.contrib import messages

def index(request):
    if request.method == 'POST':
        form = CaptchaForm(request.POST)
        if form.is_valid():
            messages.success(request, 'Success!')
        else:
            messages.error(request, 'Wrong Captcha!')
    form = CaptchaForm()
    return render(request, 'index.html', {'form': form})

We use the POST method since we are sending data to the server.

If the user enters the correct code as indicated by the captcha, we display a success message. Otherwise, an error message is displayed. We then pass the captcha as a dictionary to the render() function.

The templates

Inside the templates folder, create the index.html file.

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <title>Captcha</tile>

    <link
      href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0/dist/css/bootstrap.min.css"
      rel="stylesheet"
      integrity="sha384-wEmeIV1mKuiNpC+IOBjI7aAzPcEZeedi5yW5f2yOq55WWLwNGmvvx4Um1vskeMj0"
      crossorigin="anonymous"
    />
  </head>
  <body>
    <h2 class="text-center mt-3 text-info">Django Catcha</h2>
    {% if messages %}
      {% for message in messages %}
        <div class="alert text-center mt-5 alert-{{ message.tags }}">
           {{ message }}
        </di>
      {% endfor %}
    {% endif %}
    <form action="" method="post" class="text-center mt-5" novalidate>
      {% csrf_token %}
      {{ form.captcha }}
      <input type="submit" classs="btn btn-primary" value="submit">
    </form>
  </body>
</html>

We use Bootstrap to style the web page. The csrf_token prevents a XSS attack that may occur when accepting user input.

The novalidate attribute is there to ensure the user validates all the entries before proceeding. We display the captcha using {{ form.captcha }}.

Configuring the URLs

Let’s start with the project-level URLs. Go to project/urls.py.

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

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

We include the captcha.urls as explained in the documentation. Then, for the app-level URLs, create a urls.py file in the captcha_app folder.

from django.urls import path
from .views import index


urlpatterns = [
    path('', index, name="index"),
]

Run the migration command, and start the local server.

python3 manage.py migrate
python3 manage.py runserver

You will see something similar to the screenshot below.

Conclusion

In this tutorial, we learned how Django makes it easy to add a captcha to a web application. This does not end here. You will have to specify where to send the user upon successful submission of the form. You can easily do that in your settings.py file using this:

LOGIN_REDIRECT_URL = 'home'


Here, we assume the captcha is for logging into the website. We also assume the home page URL alias is home. For this project, we use 'index'. This will redirect the user to the home page of the website.

Of course, there is more to this than making adjustments to the project’s settings. You can check Django documentation or consult other online resources. Again, check my GitHub page for the full code. Have a nice day!