Django file upload with Ajax-fueled progress bar

Viewed 1732

I am relatively new to Django and even newer to JavaScript, so excuse my greenhorn question. The situation is like this:

1) I have a website for file uploading, coded out in Django, with some of the logic like the one below:

def page_query(request):
    ...
    if request.method == 'POST':
       ...
       file_entry = file_form(request.POST, request.FILES)

       if file_entry.is_valid():
           if request.FILES.get('filename', False) != False:
               f = request.FILES['filename']
               fname = time_id + '_' + case_id + '_.ext'
               file_check = data_admin.upload_file(f, fname, upload_path)
               upload_file_path = os.path.join(upload_path, fname)

data_admin.upload_file() is a custom function defined in another module of my project with function boiling down to:

with open(upload_path + fname, 'wb+') as destination:
    for chunk in f.chunks():
        destination.write(chunk)

2) I wanted to add some sort of upload progress indication to my website, and in a lot of sources I have seen people recommending jQuery's Ajax solution, which boils down to the code below:

$(document).ready(function() {

  $('#form_id').on('submit', function(event) {
    // event.preventDefault();

    var post_data = new FormData($("#form_id")[0]);

    $.ajax({
        xhr: function() {
          var xhr = new window.XMLHttpRequest();

          xhr.upload.addEventListener("progress", function(evt) {
            var percent = Math.round(evt.loaded/evt.total * 100)
            console.log(percent)
            $('#complaint_query_button').attr('disabled', true)
            $('#complaint_query_button').get(0).innerText = "Upload status: " + percent + '%'
          }, false);

          xhr.upload.addEventListener("load", function(evt) {
            $('#complaint_query_button').css('background-color', 'green').delay(2000)
            $('#complaint_query_button').get(0).innerText = "COMPLETE, refreshing..."
            // setTimeout(location.reload.bind(location), 10000);

          }, false);

          return xhr;
        },
          url: window.location.href,// to allow add and edit
          // url: window.location.reload(),
          type: "POST",
          data: post_data,
          processData: false,
          contentType: false,
          success: function(result) {
              //
        }
      });
  })

The above solution worked for me like a charm, and I have a submit button which indicates upload's progress in %s, however, I think I do not completely understand what is exactly happening with all that in place. I have seen files attached in the file input HTML elements get uploaded twice to my destination on the server. Moreover, the upload progress indicated on the submit button by Ajax command does not line up with my browser's upload progress info displayed in the bottom-left side of the page. I am really confused by the above - am I creating 2 upload streams (one with Django, the other with Ajax)? How can I reconcile them? I am open to suggestions on how to deal with this issue, or maybe there is a Django-native module which takes care of file upload progress?

Thank you.

UPDATE 19 Sep 2018 Still had no luck figuring this one out. Would be obliged to anyone who'll find a moment to share their opinion with me. Apologies for a shameless bump up.

1 Answers

Well, after a big trial and error run with this matter, I have finally cracked the problem - the url argument had to be changed from "window.location.href" to "#", and all problems I have described above stopped immediately. After adding in views.py's page_query function a JSON response at the end of the POST method block, I ended up having a web site which does file transfer and updates the user about the status of the upload without a need to be re-rendered after each form submission.

Would love to learn from someone more knowledgeable than myself, what does this "#" sign in there really do in there, as it has been a game-changer for me.

Related