DevB2F
DevB2F

Reputation: 5075

jquery elements with django forms

I am using jquery elements that a user can drag and drop. I post the order of the elements to django using ajax.

Inside the django view I am able to work with the data that is posted from ajax.

Django views:

#this is the view where the jquery elements are being ordered by the user
def inside_exam(request):


    if request.method=='POST':
        form = MyForm(request.POST)
        if form.is_valid():
           #here I am able to retrieve the data from ajax and save it to a django model, code not shown here

           return redirect('exam_results')


#the view redirected to from the inside_exam view
def exam_results(request):

    #here I set the score for the exam and set the context, code not shown here 

    print(“all is set”)
    return render(request, 'quizresults.html', context)

The print(“all is set”) is executed and I am able to print the html for quizresults.html in the browser. No errors are in the terminal window and this is shown in the terminal: "GET /exam_results/ HTTP/1.1" 200 8981.

But the same template is still shown, it is not showing the quizresults.html template. Any idea why the render(request, 'quizresults.html', context) is not working as expected?

By the way: when I use a django form without the jquery, everything works fine and the quizresults.html template is shown.

Since I want to show the user another template, but not update the current template, is ajax maybe not the correct way to send the jquery data in this case? If not, what would be a better way?

Edit, ajax code:

function dataToSend() {
    {% load static %}
     var node2 = document.getElementById('sortable');
     var idsInOrder = $("#sortable").sortable('toArray');
     console.log("the ids");
     console.log(idsInOrder);

     var fd = new FormData();
     for(var i=0; i<idsInOrder.length; i++) {
          j = i+1
          fd.append('a'+j, idsInOrder[i]);
     }

     $.ajax({
       type: 'POST',
       data: fd,
       cache: false,
       processData: false,
       contentType: false
     }).done(function(data) {
       //The data from the quizresults.html template is printed out here, but that template is not shown, the template in the browser is still the insidequiz.html template.
       console.log("the data");
       console.log(data);
     });
 }


 window.onload = function init() {
     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]);
           if (cookie.substring(0, name.length + 1) === (name + '=')) {
             cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
             break;
           }
         }
       }
       return cookieValue;
     }

     var csrftoken = getCookie('csrftoken');

     function csrfSafeMethod(method) {
         return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
     }
     $.ajaxSetup({
         beforeSend: function(xhr, settings) {
             if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
                xhr.setRequestHeader("X-CSRFToken", csrftoken);
             }
         }
     });
};

Upvotes: 1

Views: 949

Answers (2)

Sachin
Sachin

Reputation: 3664

Using redirect shortcut method in Django will return a HttpResponseRedirect object back to the AJAX, which it will be processed as a 302 Found status code, which then will make another request to the redirected resource and get the content. This does not seem to be the right way to do it, even though you get the content.

You can use the method exam_results to do the other work and return the required context, which shall be used to return the HttpResponse object using render method.
Then, with the data you get, you can replace the document with the template you receive.

Solution:

# views

#this is the view where the jquery elements are being ordered by the user
def inside_exam(request):
    if request.method=='POST':
        form = MyForm(request.POST)
        if form.is_valid():
           #here I am able to retrieve the data from ajax and save it to a django model, code not shown here

           context = exam_results(request)

           return render(request, 'quizresults.html', context)


# method to set the score for the exam
# return context from this method
def exam_results(request):

    #here I set the score for the exam and set the context, code not shown here 

    # build context
    return context


 # javascript

     $.ajax({
       type: 'POST',
       data: fd,
       cache: false,
       processData: false,
       contentType: false
     }).done(function(data) {
       //The data from the quizresults.html template is printed out here, but that template is not shown, the template in the browser is still the insidequiz.html template.
       console.log("the data");
       console.log(data);

       // replace the page with the new template
       var newDoc = document.open("text/html", "replace");
       newDoc.write(data);
       newDoc.close();

       // update the url
       window.history.pushState('', 'title', "newurl");
     });

Ref: History API MDN

Upvotes: 1

DevB2F
DevB2F

Reputation: 5075

I figured that ajax makes things complicated when it comes to redirecting. What I ended up doing was to create an HTML form (that is hidden) and then post that form to a url using javascript. No need for ajax.

HTML code:

 <form id="form1" action='{% url 'inside_exam' %}' method="post" style="display:none;">
   {% csrf_token %}
 </form>

 <p> <button type='submit' style="visibility" class="button button-long button-primary" onclick="sendData(this);">Send</button></p>

javascript code:

function sendData() {
  var idsInOrder = $("#sortable").sortable('toArray');
  var form = document.getElementById('form1');    
  for(var i=0; i<idsInOrder.length; i++) {
      j = i+1
      var hiddenField = document.createElement("input");
      hiddenField.setAttribute("type", "hidden");
      hiddenField.setAttribute("name", 'a'+j);
      hiddenField.setAttribute("value", idsInOrder[i]);

      form.appendChild(hiddenField);
  }
  console.log("form is:");
  console.log(form);

  form.submit();
}

Upvotes: 0

Related Questions