Django + AJAX : How to use AJAX in Django Templates

AJAX or Asynchronous JavaScript And XML is a set of web development techniques using web technologies on the client-side to create asynchronous web requests.

In simpler words, AJAX allows web pages to be updated asynchronously by exchanging data with a web server behind the scenes. This means that updating parts of a web page is possible, without reloading the whole page.

We can make AJAX requests from Django templates using JQuery. With the jQuery AJAX methods, you can request text, HTML, XML, or JSON from a remote server using both HTTP Get and HTTP Post and you can load the external data directly into the selected HTML elements of your web page.

In this tutorial, we will learn how to make AJAX HTTP GET and POST requests from Django templates.

 

Making AJAX GET requests with Django and JQuery

The HTTP GET method is used to retrieve data from the server.

In this section, we will create a signup page where we will check the availability of a username using JQuery and AJAX in Django templates. This is a very common requirement for most modern apps.

 

views.py

from django.contrib.auth.models import User
from django.contrib.auth.decorators import login_required
from django.http import JsonResponse
from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth import login, authenticate
from django.shortcuts import render, redirect
from django.views.generic.edit import CreateView
from django.urls import reverse_lazy


@login_required
def home(request):
    return render(request, 'home.html')


class SignUpView(CreateView):
    template_name = 'signup.html'
    form_class = UserCreationForm
    success_url = reverse_lazy('home')

    def form_valid(self, form):
        valid = super().form_valid(form)
        login(self.request, self.object)
        return valid


def validate_username(request):
    """Check username availability"""
    username = request.GET.get('username', None)
    response = {
        'is_taken': User.objects.filter(username__iexact=username).exists()
    }
    return JsonResponse(response)

So here we have three views first one is the home view which is basically rending a simple template.

Next is SignUpView inheriting from Django’s CreateView class to create users using Django’s builtin UserCreationForm class which provides a very basic form for user signup and on successful signup we are logging in the user and then redirecting them to the homepage.

 

Finally  validate_username view is our AJAX view which returns a JSON object with boolean from the username exists query.

The JsonResponse class returns an HTTP response with an application/json content type, converting the given object into a JSON object. So if the username already exists in the database it will return a JSON object as follows.

{ 'is_taken': true }

urls.py

from django.urls import path
from .views import  home, SignUpView, validate_username

urlpatterns = [
    path('', home, name='home'),
    path('signup', SignUpView.as_view(), name='signup'),
    path('validate_username', validate_username, name='validate_username')
]

home.html

<h1>Welcome, {{ user.username }}!</h1>

signup.html

{% load crispy_forms_tags %}
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css"
        integrity="sha384-JcKb8q3iqJ61gNV9KGb8thSsNjpSL0n8PARn9HuZOnIxN0hoP+VmmDGMN5t9UJ0Z" crossorigin="anonymous">
</head>

<body>
    <div class="container mt-5 w-50">
        <form id="signupForm" method="POST">
            {% csrf_token %}
            {{ form|crispy  }}
            <input type="submit" name="signupSubmit" class="btn btn-success btn-lg" />
        </form>
    </div>

    {% block javascript %}
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>

    <script>
        $(document).ready(function () {
            // catch the form's submit event
            $('#id_username').keyup(function () {
                // create an AJAX call
                $.ajax({
                    data: $(this).serialize(), // get the form data
                    url: "{% url 'validate_username' %}",
                    // on success
                    success: function (response) {
                        if (response.is_taken == true) {
                            $('#id_username').removeClass('is-valid').addClass('is-invalid');
                            $('#id_username').after('<div class="invalid-feedback d-block" id="usernameError">This username is not available!</div>')
                        }
                        else {
                            $('#id_username').removeClass('is-invalid').addClass('is-valid');
                            $('#usernameError').remove();

                        }

                    },
                    // on error
                    error: function (response) {
                        // alert the error if any error occured
                        console.log(response.responseJSON.errors)
                    }
                });

                return false;
            });
        })
    </script>
    {% endblock javascript %}
</body>

</html>

Let’s breakdown the template is small pieces to understand better.

Inside the head tag, we are loading the bootstrap from CDN you can download the library and serve it from static folders as well.

<form id="signupForm" method="POST">
            {% csrf_token %}
            {{ form|crispy  }}
<input type="submit" name="signupSubmit" class="btn btn-success btn-lg" />
</form>

Then we are rending the Django form using crispy tag for styling.

<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>

Next, inside the javascript block, we are pulling JQuery from google CDN you can download it locally as well.

$(document).ready(function () {
    ( .... )
})

Then we have another script having ready method, The ready() method is used to make a function available after the document is loaded. The code written inside the $(document ).ready() method will run once the page DOM is ready to execute JavaScript code.

$('#id_username').keyup(function() {
    // create an AJAX call
    $.ajax({
        data: $(this).serialize(), // get the form data
        url: "{% url 'validate_username' %}",
        // on success
        success: function(response) {
            if (response.is_taken == true) {
                $('#id_username').removeClass('is-valid').addClass('is-invalid');
                $('#id_username').after('<div class="invalid-feedback d-block" id="usernameError">This username is not available!</div>')
            } else {
                $('#id_username').removeClass('is-invalid').addClass('is-valid');
                $('#usernameError').remove();

            }

        },
        // on error
        error: function(response) {
            // alert the error if any error occured
            console.log(response.responseJSON.errors)
        }
    });

    return false;
});

The AJAX method is triggered by keyup function it takes two parameters data and the URL  upon successful completion of requests one of either callback i.e success and error gets invoked. On a successful call, we have a conditional statement to add or remove the invalid class from the input form field and the return false at the end of the script prevents forms from submitting, therefore, preventing page reload.

Save the files and run the server you should see AJAX in action.

Making AJAX POST requests with Django and JQuery

The HTTP POST method is used to send data to the server.

In this section, we will learn how to make POST requests with JQuery and AJAX in Django templates.

 

We will create a contact form and save the data provided by the user into the database with JQuery and AJAX.

 

models.py

from django.db import models

class Contact(models.Model):
    name = models.CharField(max_length=100)
    email = models.EmailField()
    message = models.TextField()

    def __str__(self):
        return self.name

forms.py

from django import forms
from .models import Contact


class ContactForm(forms.ModelForm):
    class Meta:
        model = Contact
        fields = '__all__'

urls.py

from django.urls import path
from .views import contact_form

urlpatterns = [
   path('contact-form/', contact_form, name='contact_form')
]

views.py

from django.http import JsonResponse
from django.shortcuts import render
from .forms import ContactForm

def contact_form(request):
    form = ContactForm()
    if request.method == "POST" and request.is_ajax():
        form = ContactForm(request.POST)
        if form.is_valid():
            name = form.cleaned_data['name']
            form.save()
            return JsonResponse({"name": name}, status=200)
        else:
            errors = form.errors.as_json()
            return JsonResponse({"errors": errors}, status=400)

    return render(request, "contact.html", {"form": form})

In the view, we are verifying the ajax request with request.is_ajax() method then if the form is valid we are saving it to the database and returning JSON object with status code and name and for an invalid form, we are returning the form errors with status code 400 i.e bad request.

contact.html

{% load crispy_forms_tags %}

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Contact us</title>
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css"
        integrity="sha384-JcKb8q3iqJ61gNV9KGb8thSsNjpSL0n8PARn9HuZOnIxN0hoP+VmmDGMN5t9UJ0Z" crossorigin="anonymous">

</head>

<body>
    <div class="container mt-5 w-50">
        <form id="contactForm" method="POST">
            {% csrf_token %}
            {{ form|crispy  }}
            <input type="submit" name="contact-submit" class="btn btn-success btn-lg" />
        </form>
    </div>
    {% block javascript %}
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>

    <script>
        $(document).ready(function () {
            // catch the form's submit event
            $('#contactForm').submit(function () {
                // create an AJAX call
                $.ajax({
                    data: $(this).serialize(), // get the form data
                    type: $(this).attr('method'), // GET or POST
                    url: "{% url 'contact_form' %}",
                    // on success
                    success: function (response) {
                        alert("Thankyou for reaching us out " + response.name);
                    },
                    // on error
                    error: function (response) {
                        // alert the error if any error occured
                        alert(response.responseJSON.errors);
                        console.log(response.responseJSON.errors)
                    }
                });
                return false;
            });
        })
    </script>
    {% endblock javascript %}
</body>

</html>

Let’s break down the template in smaller modules to understand it better.

First, we are importing bootstrap inside the head tag from CDN then inside the body, we are reading the form with crispy tag for styling.

 

Then inside the javascript block first, we are loading JQuery from the CDN.

 <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>

Then Inside the $(document).ready()function we have our AJAX method.

$('#contactForm').submit(function() {
    // create an AJAX call
    $.ajax({
        data: $(this).serialize(), // get the form data
        type: $(this).attr('method'), // GET or POST
        url: "{% url 'contact_form' %}",
        // on success
        success: function(response) {
            alert("Thankyou for reaching us out " + response.name);
        },
        // on error
        error: function(response) {
            // alert the error if any error occured
            alert(response.responseJSON.errors);
            console.log(response.responseJSON.errors)
        }
    });
    return false;
});

On form submit we are invoking the ajax method which is serializing the form data and sending it to the given URL. On a successful call, we are showing an alert dialog with a dynamic message based on the user name.

Making AJAX POST requests with Django and JQuery using Class-based views

views.py

from django.views.generic.edit import FormView
from django.http import JsonResponse



class ContactFormView(FormView):
    template_name = 'contact.html'
    form_class = ContactForm

    def form_valid(self, form):
        """
        If the form is valid return HTTP 200 status 
        code along with name of the user
        """
        name = form.cleaned_data['name']
        form.save()
        return JsonResponse({"name": name}, status=200)

    def form_invalid(self, form):
        """
        If the form is invalid return status 400
        with the errors.
        """
        errors = form.errors.as_json()
        return JsonResponse({"errors": errors}, status=400)

We just need to return a JSON object from the form_valid() method of FormView, you can also use other generic class-based views by overriding post() method.