Django with Ajax, a modern client-server communication practise

1666323

Intro

We all know that Django is a powerful framework. Many of us deals with posting data from a HTML form to a Django view and process it. You should have never cared of Ajax way of posting the data. Some of you tried AJAX but faced  few painful intros to setup a perfectly running Django-Ajax implementation. So,I came up this time to tell you how to do that.After this tutorial you will feel quite comfortable about implementing ajax posts and also will keep this article as a reference for future. Source code for upcoming tutorial available at following link.

 

What is AJAX?

Simply put AJAX is about updating parts of a web page, without reloading the whole page.

Suppose we need to update any parts of our website page ,then we must use Ajax. For posting data back to server ajax is required. Now why we should use it with Django ?. I believe following things will answer you.

  •  Using Ajax, we can craft data format that sent back to server.
  •  We can handle the situations like successful post or failure or error.
  • Drop all burden on client rather than server wherever it is possible.
  • For implementing progress bars ajax post is the best way.
  • Drop messages framework to display something ,I hate it. Use JSON response returned from Ajax post to wake up cool notification models etc.

If you didn’t understand the above points , cool. I too didn’t once. The simple thing I am gonna show is , how to post something back to server from HTML and collect acknowledgement that returned back.

Let us begin the show

We are going to see the demonstration from scratch. Let us create a Django project for that. Remember we am playing with Django >= 1.7 here.

$ pip install Django==1.7.3

This installs Django1.7 on your system.

$ django-admin startproject ajaxpost
#Now create an app called mainapp inside ajaxpost
$ django-admin startapp mainapp

Then the directory structure will be in this way.

 

Selection_049

Now let us add the superuser to begin with. Default db will be SQilte3. First do a migration for django to create default user tables in db. So do this.

$ python manage.py migrate

Now create a super user for admin.

$ python manage.py createsuperuser

That’s it. Now we are going to create a home page which has the email field and a password for collecting user data. It is to show data passage from ( client -> server ,server -> client) . Simple,but extremely useful in 100 use-cases.

After creation of superuser ,just create a view for our home page. ajaxpost/urls.py looks like below

#ajaxpost/urls.py

from django.contrib import admin
from mainapp import views

urlpatterns = patterns('',
 url(r'^admin/', include(admin.site.urls)),
 url(r'^',views.home , name=u'home')
)

Now modify the views of mainapp to the following.

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


def home(request):
     return JsonResponse({"hello":"pythonist"})

Now just save and do a runserver. Next Go to http://localhost:8000 and you will find this thing.

$ python manage.py runserver

Selection_042

See how simple it is to send a Json response from a Django1.7 view. Now we are going to crete a HTML file for our home page and try to take data from it to create user. For that create a folder called templates in your project root and make a file called base.html. tree structure of our project looks this.

Selection_043

Ok. Now I am adding  template directories location to settings.py. Add this line to ajaxpost/settings.py

     TEMPLATE_DIRS = (
        BASE_DIR + '/templates/',
                 )

Now Django can find template files. So add this HTML content to templates/base.html

 <html>
     <head>
          <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" rel="stylesheet">
          <link href="http://getbootstrap.com/examples/signin/signin.css" rel="stylesheet">
     </head>

 <body>

 <div class="container">

 <form class="form-signin" method="POST">
    {% csrf_token %}
      <h2 class="form-signin-heading">Enter Details</h2>
     <label for="inputEmail" class="sr-only">Email address</label>
     <input type="email" id="inputEmail" class="form-control" placeholder="Email               address" required autofocus>
     <label for="inputPassword" class="sr-only">Password</label>
     <input type="password" id="inputPassword" class="form-control"  placeholder="Password" required>
     <button id="submit" class="btn btn-lg btn-primary btn-block" type="submit">Sign in</button>
 </form>

 </div>

 <script src="http://code.jquery.com/jquery-2.1.4.min.js"></script>

</body>
</html>

When you fire runserver and go to http://localhost:8000 , you will find a nice bootstrap Enter details form like this.

I hope things are clear. Follow from the top , if you are in doubt.

Now comes the Ajax part

Instead of doing a normal submit , let us have an Ajax post block in our HTML file. Django relies on csrf token for the validity of data posted to the server. So in addition to data , we should send csrf-token. In default django submission,it is automatically sent. But in case of Ajax , we need to take care of that.

Take the below JS code as Granted and place it in  a new <script></script> tag in base.html

 
 <script>

//For getting CSRF token
function getCookie(name) {
          var cookieValue = null;
          if (document.cookie && document.cookie != '') {
                var cookies = document.cookie.split(';');
          for (var i = 0; i < cookies.length; i++) {
               var cookie = jQuery.trim(cookies[i]);
          // Does this cookie string begin with the name we want?
          if (cookie.substring(0, name.length + 1) == (name + '=')) {
            cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
              break;
             }
          }
      }
 return cookieValue;
}


//For doing AJAX post

//When submit is clicked
 $("#submit").click(function(e) {

//Prevent default submit. Must for Ajax post.Beginner's pit.
 e.preventDefault();

//Prepare csrf token
 var csrftoken = getCookie('csrftoken');


//Collect data from fields
 var email = $('#inputEmail').val();
 var password = $('#inputPassword').val();

//This is the Ajax post.Observe carefully. It is nothing but details of where_to_post,what_to_post
//Send data  
 $.ajax({
       url : window.location.href, // the endpoint,commonly same url
       type : "POST", // http method
       data : { csrfmiddlewaretoken : csrftoken, 
       email : email,
       password : password
 }, // data sent with the post request

 // handle a successful response
 success : function(json) {
 console.log(json); // another sanity check
 //On success show the data posted to server as a message
 alert('Hi   '+json['email'] +'!.' + '  You have entered password:'+ json['password']);
 },

 // handle a non-successful response
 error : function(xhr,errmsg,err) {
 console.log(xhr.status + ": " + xhr.responseText); // provide a bit more info about the error to the console
 }
 });
});
</script>
 Now Don’t forget to place {% csrf_token %} next to the form tag in base.html. Let us modify the mainapp/views.py.
from django.shortcuts import render
from django.http import JsonResponse

def home(request):
    if request.method == 'POST':
        #POST goes here . is_ajax is must to capture ajax requests. Beginner's pit.
        if request.is_ajax():
            #Always use get on request.POST. Correct way of querying a QueryDict.
            email = request.POST.get('email')
            password = request.POST.get('password')
            data = {"email":email , "password" : password}
            #Returning same data back to browser.It is not possible with Normal submit
            return JsonResponse(data)
    #Get goes here
    return render(request,'base.html')
Now everything for demonstration is built. We need to wrap up things and do a runserver. Before that complete templates/base.html file looks this way.
   
 <html>
 <head>
 <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" rel="stylesheet">
 <link href="http://getbootstrap.com/examples/signin/signin.css" rel="stylesheet">
 </head>

 <body>

 <div class="container">

 <form class="form-signin" method="POST">
      {% csrf_token %}
      <h2 class="form-signin-heading">Enter Details</h2>
      <label for="inputEmail" class="sr-only">Email address</label>
      <input type="email" id="inputEmail" class="form-control" placeholder="Email address" required autofocus>
      <label for="inputPassword" class="sr-only">Password</label>
      <input type="password" id="inputPassword" class="form-control" placeholder="Password" required>
      <button id="submit" class="btn btn-lg btn-primary btn-block" type="submit">Sign in</button>
 </form>

 </div>

 <script src="http://code.jquery.com/jquery-2.1.4.min.js"></script>
 <script>

//For getting CSRF token
function getCookie(name) {
       var cookieValue = null;
       if (document.cookie && document.cookie != '') {
         var cookies = document.cookie.split(';');
         for (var i = 0; i < cookies.length; i++) {
         var cookie = jQuery.trim(cookies[i]);
         // Does this cookie string begin with the name we want?
         if (cookie.substring(0, name.length + 1) == (name + '=')) {
             cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
             break;
          }
     }
 }
 return cookieValue;
}


//For doing AJAX post
 $("#submit").click(function(e) {

 e.preventDefault();

 var csrftoken = getCookie('csrftoken');

 var email = $('#inputEmail').val();

 var password = $('#inputPassword').val();

//This is the Ajax post.Observe carefully. It is nothing but details of where_to_post,what_to_post
 
 $.ajax({
         url : window.location.href, // the endpoint,commonly same url
         type : "POST", // http method
         data : { csrfmiddlewaretoken : csrftoken, 
         email : email,
         password : password
 }, // data sent with the post request

 // handle a successful response
 success : function(json) {
      console.log(json); // another sanity check
      //On success show the data posted to server as a message
      alert('Hi '+json['email'] +'!.' + ' You have entered password:'+      json['password']);
 },

 // handle a non-successful response
 error : function(xhr,errmsg,err) {
 console.log(xhr.status + ": " + xhr.responseText); // provide a bit more info about the error to the console
 }
 });
});

</script>

</body>
</html>
Ok. Now fire up the server using
$ python manage.py runserver
Now I went to http://localhost:8000 and entered these details.
email : pikachu@pokemon
password: charizard
When I click sign in this is what I got.
Selection_048
Hurray. We got it. Data is passed from client to server using Ajax and then server sent same data to client as JSON to display alert message.
This is how we pass information to the server using Ajax . Ajax is mainly used for long polling. Long polling is process in which, Ajax sends request from client to server asking the latest information.Then it updates the contents of HTML with data obtained. Here, we  stressed four things. In case of failure of any one, Ajax post may not work.Those things are listed below.
  • {% csrf_token %} just below form tag.
  • csrfmiddlewaretoken in Ajax POST data.
  • is_ajax() handler in Django view.
  • get(‘parameter’) method on request.POST

What is new in Django 1.7?

 In Django 1.7 ,we have JsonResponse which directly encodes a Python dictionary to JSON object without dumping data .
from django.http import JsonResponse

#Usage in view
return JsonResponse({"foo":"bar"})
 Before you used to do this like
import json
return HttpResponse(json.dumps({"foo":"bar"}), content_type="applciation/json")

Conclusion

I hope you got something from this tutorial. I faced problems when I started doing Ajax posts a year back. All tutorials on web misses one or more important things , so things won’t work. That gives us great frustration. I here showed a simple, working example of Ajax post in Django. Use it. source code is available at this link.

Advertisements

14 thoughts on “Django with Ajax, a modern client-server communication practise

  1. Hi! I followed your short tutorial, and most things worked except for the final data transfer, and I don’t get our programmed alert message. The debugging dev tools in Chrome report “Uncaught ReferenceError: $ is not defined” on this line of your code: (for me it’s line 24 & 25)

    //When submit is clicked
    $(“#submit”).click(function(e) {

    Any suggestions? Meanwhile I will troubleshoot this further.

      1. Thanks for replying. Oops I found the problem. It was simply that I pasted the jQuery stuff at the top before the declaration of #submit. Kind of silly, but anyway I pasted all the jQuery towards the bottom (where it should go anyway) and it behaves as expected.

  2. Amazing post!!!! I was looking for this tutorial since such a long time! Rest of the tutorials on internet are just too complicated! Thanks again!

  3. Worked perfectly! This is maybe the 5th tutorial I’ve read and the one that finally made sense!
    Quick note, I don’t know if it’s my display or what but from what I can tell your view has some syntax errors:
    Says:
    if request.is_ajax():
    #Always use get on request.POST. Correct way of querying a QueryDict.
    email = request.POST.get(’email password = request.POST.get(‘password data = {“email”:email , “password” : password}
    #Returning same data back to browser.It is not possible with Normal submit

    should be:
    if request.is_ajax():
    #Always use get on request.POST. Correct way of querying a QueryDict.
    email = request.POST.get(’email’)
    password = request.POST.get(‘password’)
    data = {“email”:email , “password” : password}
    #Returning same data back to browser.It is not possible with Normal submit

  4. Seriously, thanks. I’ve spent 2 or 3 days trying to figure this out (I’m new to ajax, bad at js) but trying your example, then rewriting my form following your example, got it working in about 30 minutes. You’re awesome.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s