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.
Pre-Requirements
I am assuming you have a basic working knowledge of Django. Therefore, I am not going into the project setup part in case you need help with that I recommend reading the following articles.
This is a very basic project with an app called AJAX and I am using bootstrap and Django crispy form for styling.
Github repo -https://github.com/TheAbhijeet/Django-with-JQuery-and-AJAX
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 Userfrom django.contrib.auth.decorators
import login_requiredfrom 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_requireddef 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 occurred
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 occurred
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.