How to add file upload progress bar to Django webs

2019-08-03 23:53发布

问题:

I am trying to use django-progressbarupload app to add progress bar to my Django app. But it is not working .... The django-progressbarupload app templates tags are loading fine and also file is uploading to the server but progress bar is not showing up ...and their is no javascript error on the console... I have followed this tutorial

Can anyone tell how to add progress bar to Django app

回答1:

It clearly is a bug in webkit based browsers, here's the relevant thread:

Ajax form upload progress bar

Also here is the relevant github issue:

https://github.com/ouhouhsami/django-progressbarupload/issues/2

To comprehend, webkit doesn't allow to make ajax calls while uploading file, the usual workaround is to use dynamically created iframe (mentioned in above SO thread).



回答2:

It's not the best solution (and not so consistent) but it will be the easiest to implement.

Create js file e.g. progress_bar.js

In your admin.py

class YouSuperModelAdmin(admin.ModelAdmin):
    ...
    class Media:
        js = ['/static/js/progress_bar.js']
    ...

In progress_bar.js

(function($){   
$(function(){
    $(document).ready(function() {
        $( "#form_id" ).submit(function( event ) {
          event.preventDefault();

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

          $.ajax({
              xhr: function() {
                var xhr = new window.XMLHttpRequest();
                var new_div = document.createElement('div');

                new_div.innerHTML = '<progress id="progressBar" value="0" max="100" style="width:300px;"></progress><h3 id="status"></h3><p id="loaded_n_total"></p>';
                document.getElementsByClassName('submit-row')[0].appendChild(new_div)

                xhr.upload.addEventListener("progress", progressHandler, false);
                xhr.addEventListener("load", completeHandler, false);
                xhr.addEventListener("error", errorHandler, false);
                xhr.addEventListener("abort", abortHandler, false);

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

The idea is to prevent default form submition, create new XMLHttpRequest, inject progressbar with messages and then send the data showing the process.

It is very important to set processData: false, contentType: false, otherwise it will not handle the file in the form

And finaly in your progress_bar.js set event handlers for the progress bar itself.

function _(el) {
  return document.getElementById(el);
}

function progressHandler(event) {
  _("loaded_n_total").innerHTML = "Uploaded " + event.loaded + " bytes of " + event.total;
  var percent = (event.loaded / event.total) * 100;
  _("progressBar").value = Math.round(percent);
  _("status").innerHTML = Math.round(percent) + "% uploaded... please wait";
}

function completeHandler(event) {
  _("status").innerHTML = event.target.responseText;
  _("progressBar").value = 0; //wil clear progress bar after successful upload
}

function errorHandler(event) {
  _("status").innerHTML = "Upload Failed";

}

function abortHandler(event) {
  _("status").innerHTML = "Upload Aborted";
}

NOTE: In order not to have html page appearing under the form after success you have to change your view that returns HttpResponse object or simply change the window.location.

The described method should work for any form with django.