Using XMLHttpRequest with Django - setting csrf token

GET request

Example below inform user about the "Sending..." state (interval between sending data and receiving answer from server), eventual error state or about no answer situation. The last situation, we could simulate by specifying a timeout in request and then, turning off the server, ajax call will trigger the onerror handler: "No response ...". By specifying a timeout with a non-numeric value or a negative number, we can simulate a server error (500).

<script>

function getXHR(){
    var xhr = false;
    if (window.XMLHttpRequest) {
        xhr = new XMLHttpRequest();
    } else { //code for IE6, IE5
        xhr = new ActiveXObject("Microsoft.XMLHTTP");
    }
    return xhr;
}

function GetData() {
    var milisec1 = Date.now();

    // Instantiate XHR
    xhr = getXHR();
    if(!xhr) {
        alert("Ajax is not supported by your browser!");
        return;
    }

    // Handle Response from Server
    xhr.onreadystatechange = function () {
        if (xhr.readyState < 4)
            document.getElementById('div1').innerHTML = "Sending...";
        else if (xhr.readyState === 4) {
            if (xhr.status == 200 && xhr.status < 300){
                var milisec2 = Date.now();
                var dt = (milisec2 - milisec1).toString();
                document.getElementById('div1').innerHTML = xhr.responseText + " (" + dt + " milisec delay)";
            }
            else
                document.getElementById('div1').innerHTML = "Error: " + xhr.status;
        }
    }
    xhr.onerror = function() {
        document.getElementById('div1').innerHTML = "Error: No response from server.";
    }

    // Send data to server
    var timeout = document.getElementById('timeout').value;
    xhr.open('GET', 'reply/?timeout='+timeout);
    xhr.send(null);
}

window.onload=function(){
    var button1 = document.getElementById('test1');
    button1.onclick = GetData;
}

</script>

<html>

    Server response:<div id="div1" style="height:1.5em; width:100%; border: 1px solid black;"></div>
    <p>
    <button id="test1" type="button" >Test</button>
    <label>server delay:</label>
    <input type="text" value="0" id="timeout" size="3"/>seconds
    </p>

</html>
Server response:

seconds

POST request

For POST requests, in order to avoid "Forbidden (CSRF token missing or incorrect.)" / error 403 reply from Django, without using jquery, we could set csrf token for XMLHttp request in two ways:
  • by including in template, after the tag:
  • "{% csrf_token %}"
    which result in hidden variable:
    <input type='hidden' name='csrfmiddlewaretoken' value='...' >/
    that we read in javascript:
    var csrf_token = document.getElementsByName("csrfmiddlewaretoken")[0].value;

    or

  • rendering csrf in views.py by:
  • from django.core.context_processors import csrf
    ...
    data.update(csrf(request))
    return render(request, page_request, data)
    which result in:
    data['csrf_token']='...' rendered in template
    that we read in javascript:
    var csrf_token = "{{ csrf_token }}"

    Finally we could set:

    xhr.setRequestHeader("X-CSRFToken", csrf_token);
    
    <script>
    
    function PostData() {
    
        // Instantiate XHR
        xhr = getXHR();
        if(!xhr) {
            alert("Ajax is not supported by your browser!");
            return;
        }
    
        // Handle Response from Server
        xhr.onreadystatechange = function () {
            if (xhr.readyState < 4)
                document.getElementById('div2').innerHTML = "Sending...";
            else if (xhr.readyState === 4) {
                if (xhr.status == 200 && xhr.status < 300){
                    document.getElementById('div2').innerHTML = xhr.responseText ;
                }
                else
                    document.getElementById('div2').innerHTML = "Error: " + xhr.status;
            }
        }
        xhr.onerror = function() {
            document.getElementById('div2').innerHTML = "Error: No response from server.";
        }
    
        // Send data to server
        xhr.open('POST', 'reply/');
        xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
        //=========================================================================
        /****  include {% csrf_token %} in template  ****/
        var csrf_token = document.getElementsByName("csrfmiddlewaretoken")[0].value;
        /****  render csrf in views.py  ****/
        //var csrf_token = "{{ csrf_token }}"
        xhr.setRequestHeader("X-CSRFToken", csrf_token );
        //=========================================================================
        jsonStr = JSON.stringify({"key1":"a","key2":"b"});
        xhr.send('name=John&json='+jsonStr);
    }
    
    window.onload=function(){
        var button2 = document.getElementById('test2');
        button2.onclick = PostData;
    }
    
    </script>
    
    <html>
    
        Server response:<div id="div2" style="height:1.5em; width:100%; border: 1px solid black;"></div>
        <p>
        <button id="test2" type="button" >Test</button>
        </p>
    
    </html>
    
    Server response:



    POST - ing data and file(s) with FormData

    
    <script>
    
    function PostData2() {
        //FileObject
        var f = document.getElementById("file").files[0];
        if(f==undefined){
            alert("Choose a file, please!");
            return;
        }
        var comment = document.getElementById("comment").value;
        var fd = new FormData();
        fd.append("fileToUpload", f);
        fd.append("comment",comment)
    
        // Instantiate XHR
        xhr = getXHR();
        if(!xhr) {
            alert("Ajax is not supported by your browser!");
            return;
        }
    
        // Handle Response from Server
        xhr.onreadystatechange = function () {
            if (xhr.readyState < 4)
                document.getElementById('div3').innerHTML = "Sending...";
            else if (xhr.readyState === 4) {
                if (xhr.status == 200 && xhr.status < 300){
                    document.getElementById('div3').innerHTML = xhr.responseText ;
                    //reset form
                    document.getElementById("file").value = "";
                    document.getElementById("comment").value = "";
                }
                else
                    document.getElementById('div3').innerHTML = "Error: " + xhr.status;
            }
        }
        xhr.onerror = function() {
            document.getElementById('div3').innerHTML = "Error: No response from server.";
        }
    
        // Send data to server
        xhr.open('POST', 'reply/');
        //=========================================================================
        /****  include  in template  ****/
        var csrf_token = document.getElementsByName("csrfmiddlewaretoken")[0].value;
        /****  render csrf in views.py  ****/
        //var csrf_token = "{{ csrf_token }}"
        xhr.setRequestHeader("X-CSRFToken", csrf_token );
        //=========================================================================
        xhr.send(fd);
    }
    
    window.onload=function(){
        var button3 = document.getElementById('test3');
        button3.onclick = PostData2;
    }
    
    </script>
    
    <html>
    
        Server response:<div id="div3" style="height:1.5em; width:100%; border: 1px solid black;"></div>
        <p>
        Comments: <input type="text" value="" id="comment" size="20"/>
        File: <input type="file" id="file" name="files">
        </p>
        <p>
        <button id="test3" type="button" >Test</button>
        </p>
    
    </html>
    
    
    Server response:

    Comments: File:



    Server side will look like that:
    def reply(request):
        req = request.read()
        print req
        if request.GET.has_key('timeout'):
            timeout = int(request.GET['timeout'])
            sleep(timeout)
            return HttpResponse("here I am!")
        if request.POST.has_key('json'):
            name = request.POST['name']
            #string
            jsonStr = request.POST['json']
            #dictionary
            jsonDict = simplejson.loads(jsonStr)
            return HttpResponse("Your request was: " + req.decode('utf-8')))
        if request.FILES:
            comment = request.POST['comment']
            file = request.FILES['fileToUpload']
            msg = "Your request was: comment=" + comment + "  file=" + file.name
            return HttpResponse(msg)
        #catch all situations, just in case
        return HttpResponse("hello!")