Django + AJAX: How to use AJAX in Django templates

by Alex
Django + AJAX: How to use AJAX in Django templates

AJAX, or asynchronous JavaScript and XML, is a set of web development methods that use client-side web technologies to create asynchronous web requests. Simply put, AJAX allows you to update web pages asynchronously, silently exchanging data with a web server. This means that updating parts of a web page is possible without reloading the entire page. We can make AJAX requests from Django templates using JQuery. The AJAX methods of the jQuery library allow us to request text, HTML, XML or JSON from a remote server using both HTTP Get and HTTP Post. The resulting data can be loaded directly into selected HTML elements of your web page. In this tutorial, we will learn how to perform AJAX HTTP GET and POST requests from Django templates.

Knowledge Requirements

I’m assuming you have a basic knowledge of Django. So I won’t go into setting up the project. This is a very simple project with an application called AJAX in which I use bootstrap and Django crispy form for styling. The Gitlab repository is https://gitlab.com/PythonRu/django-ajax

Executing 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 login page where we will check the availability of the username using JQuery and AJAX in Django templates. This is a very common requirement for most modern applications.

# ajax/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(login_url='signup')
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):
"""login validation"""
username = request.GET.get('username', None)
response = {
'is_taken': user.objects.filter(username__iexact=username).exists()
}
return JsonResponse(response)

So we have three views, the first one is home, which displays a pretty simple homepage template. Next is SignUpView, which inherits from CreateView class. It’s used to create users using the built-in Django class UserCreationForm, which provides a very simple registration form. If it succeeds, the user is logged in and redirected to the home page. Finally, validate_username is our AJAX view, which returns a JSON object with a logical value from the query that checks if the user name entered exists. The JsonResponse class returns an HTTP response with the content type application/json, converting the object passed to it into JSON format. Therefore, if the username already exists in the database, it will return the JSON object shown below.

{'is_taken': true}
# ajax/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')
]
# dj_ajax/urls.py
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('ajax/', include('ajax.urls'))
]
{# home.html #}
Hello, {{ user.username }}!
{# signup.html #}
{% load crispy_forms_tags %}
{% csrf_token %}
{{ form|crispy }}
{% block javascript %}
$(document).ready(function () {
// track the form submission event
$('#id_username').keyup(function () {
// create an AJAX callback
$.ajax({
data: $(this).serialize(), // retrieve form data
url: "{% url 'validate_username' %}",
// if successful
success: function (response) {
if (response.is_taken == true) {
$('#id_username').removeClass('is-valid').addClass('is-invalid');
$('#id_username').after('
This username is not available!
')
}
else {
$('#id_username').removeClass('is-invalid').addClass('is-valid');
$('#usernameError').remove();
}
},
// if there's an error, then
error: function (response) {
// warn about an error
console.log(response.responseJSON.errors)
}
});
return false;
});
})
{% endblock javascript %}

For a better understanding, let’s break down all the parts of the presented template in detail. Inside the head tag, we load bootstrap using a CDN. You can also save the library to your disk and give it to the client from static folders.


{% csrf_token %}
{{ form|crispy }}

Then we create a Django form using the crispy tag to style it.


Then inside the javascript block we request JQuery from google CDN, you can also download it locally.

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

Then we have another script with the ready() method. The code written inside the $(document).ready() method will run when the page’s DOM is ready for JavaScript execution.

$('#id_username').keyup(function () {
// create an AJAX callback
$.ajax({
data: $(this).serialize(), // retrieve form data
url: "{% url 'validate_username' %}",
// if successful
success: function (response) {
if (response.is_taken == true) {
$('#id_username').removeClass('is-valid').addClass('is-invalid');
$('#id_username').after('
This username is not available!
')
}
else {
$('#id_username').removeClass('is-invalid').addClass('is-valid');
$('#usernameError').remove();
}
},
// if there's an error, then
error: function (response) {
// warn about an error
console.log(response.responseJSON.errors)
}
});
return false;
});

The ajax method is triggered by the keyup function. It accepts an object with query parameters as input. When the request is successful, one of the success or error colback functions is launched. On success, we use a conditional operator to add and remove the is-valid/is-invalid classes of the input field. And return false at the end of the script prevents the forms from being sent, thus stopping the page reloading. Save the files and start 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’ll learn how to make POST requests using JQuery and AJAX in Django templates. We will create a contact form and save the data provided by the user to the database using JQuery and AJAX.

# 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
# ajax/forms.py
from django import forms
from .models import Contact
class ContactForm(forms.ModelForm):
class Meta:
model = Contact
fields = '__all__'
# ajax/urls.py
...
from .views import home, SignUpView, validate_username, contact_form
urlpatterns = [
...
path('contact-form/', contact_form, name='contact_form')
]
# ajax/views.py
...
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 check the ajax request with the request.is_ajax() method. If the form is valid, we save it to the database and return a JSON object with the status code and user name. For an invalid form we will send the client found errors with code 400, which means bad request.

{# contact.html #}
{% load crispy_forms_tags %}
Contact us
{% csrf_token %}
{{ form|crispy }}
{% block javascript %}
$(document).ready(function () {
// track the form submission 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' %}",
// if successful
success: function (response) {
alert("Thank you for contacting us " + response.name);
},
// if error, then
error: function (response) {
// let us know about the error
alert(response.responseJSON.errors);
console.log(response.responseJSON.errors)
}
});
return false;
});
})
{% endblock javascript %}

Let’s break the template into smaller modules to understand it better. First we import bootstrap into the head, using the CDN. Then inside the body we create a form with the crispy tag to style it. After that, in the first javascript block, we load jQuery from the CDN. Then inside the $(document).ready() function, we add our AJAX method.


$(document).ready(function () {
// track the form submit event
$('#contactForm').submit(function () {
// create an AJAX callback
$.ajax({
data: $(this).serialize(), // get the form data
type: $(this).attr('method'), // GET or POST
url: "{% url 'contact_form' %}",
// if successful
success: function (response) {
alert("Thank you for contacting us " + response.name);
},
// if error, then
error: function (response) {
// let us know about the error
alert(response.responseJSON.errors);
console.log(response.responseJSON.errors)
}
});
return false;
});
})

When the form is submitted, we call the ajax() method, which serializes its data and sends it to the specified URL. If successful, we show a dialog box with a message generated based on the username received.

Executing AJAX POST requests using class-based views

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

# ajax/views.py
...
from django.views.generic.edit import CreateView, FormView
...
class ContactFormView(FormView):
template_name = 'contact.html'
form_class = ContactForm
def form_valid(self, form):
"""
If the form is valid, return code 200
"...along with the username
"""
name = form.cleaned_data['name']
form.save()
return JsonResponse({"name": name}, status=200)
def form_invalid(self, form):
"""
If form is invalid, return code 400 with errors.
"""
errors = form.errors.as_json()
return JsonResponse({"errors": errors}, status=400)

Related Posts

LEAVE A COMMENT