如何在Django网站中添加文件上传进度条

3
我正在尝试使用django-progressbarupload app为我的Django应用程序添加进度条。 但是它没有起作用.... django-progressbarupload app模板标签已经成功加载,文件也上传到服务器,但进度条没有显示...控制台上也没有JavaScript错误...我已经按照这个教程进行了操作。
请问有人可以告诉我如何为Django应用程序添加进度条吗?

你有任何错误信息吗?从你的解释中,恐怕没有人能够帮助:/ - user1593705
我也尝试了他们的demoApp,但它也没有起作用... - Vaibhav Jain
3个回答

6

这不是最佳方案(也不太一致),但它将是最容易实现的。

创建 JavaScript 文件,例如 progress_bar.js。

在您的 admin.py 文件中进行如下操作:

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

在 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);

这个想法是防止默认表单提交,创建新的XMLHttpRequest,注入带有消息的进度条,然后发送显示过程的数据。

非常重要的是设置processData: false, contentType: false,否则它无法处理表单中的文件。

最后,在progress_bar.js中为进度条本身设置事件处理程序。

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";
}

注意:为了避免表单提交成功后在页面下方出现html代码,您需要更改返回HttpResponse对象的视图或者直接更改window.location。

这种方法适用于任何使用django框架的表单。


我在我的Django项目中使用了你的解决方案,并且它立刻起作用了。但是,由于我完全是新手,对于全栈开发世界还不够熟悉,我认为现在理解这个实际上是有一点困难的。目前,我的Django项目使用if method == 'POST'条件语句来开始抓取文件输入HTML元素中附加的文件。当我添加了您省略掉event.preventDefault();行的代码后,我的网站开始将这些文件保存在指定位置的2份副本中。这让我非常困惑,因为我没有在您的函数中任何地方指定存储的位置。 - Greem666
如果您不介意的话,能否请您解释一下或者给我指引一些适当的资源,让我了解一下当我声明var xhr = new window.XMLHttpRequest()并添加一些事件监听器(如进度、成功、失败等)时实际上正在发生什么?Ajax是否会为文件传输创建一个辅助流,并且是否与HTML表单的标准POST方法并行?对于我在Django中编写的处理这些文件的后端代码是否仍然会被执行? - Greem666
@Greem666 抱歉耽搁了。希望对任何人有所帮助。 XMLHttpRequest对象可帮助与服务器进行交互。 https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest 正如我在答案中解释的那样,我们使用event.preventDefault();来防止默认表单提交,然后使用相同的django逻辑。 如果我没记错的话,您将在响应中获得html主体,因此如果您想要重定向,可以更新您的admin.py以在所需视图中进行重定向。 https://docs.djangoproject.com/en/dev/ref/contrib/admin/#django.contrib.admin.ModelAdmin.get_urls - urDMG
1
@urDMG。您的示例代码对于在Django上传至S3时实例化进度条非常有效,但似乎速度过快,在实际文件上传并页面重定向之前就会显示已上传100%,需要5-10秒左右。您有什么想法,这可能是为什么? - Hayden
@Hayden 文件首先上传到临时位置 - 在此阶段,进度条从0到100%。然后将文件从临时位置复制(而不是移动)到最终目标,在此期间,进度条仍显示100%。为避免这种行为,我创建了一个自定义的FileUploadHandler,直接上传到目标文件并使用它。只需将现有的TemporaryFileUploadHandler类复制为自己的自定义处理程序,并修改代码以不创建临时文件即可。 - Hamid

2

-1

只需传递您的上传URL django_upload_url

  <!doctype html>
  <html>
    <head>
      <meta charset="utf-8">
      <title>File Uploader</title>
      <link href="https://releases.transloadit.com/uppy/v2.2.3/uppy.min.css" rel="stylesheet">
    </head>
    <body>
    <button data-toggle="modal" data-target="#UploaderModal"><strong>Upload Files</strong></button>
    <div class="modal" id="UploaderModal">
      <div class="modal-dialog">
        <div class="modal-content">
          <!-- Modal Header -->
          <div class="modal-header">
            <h4 class="modal-title">Upload Files</h4>
            <button type="button" class="close" data-dismiss="modal">&times;</button>
          </div>
            <div id="drag-drop-area"></div>
          </div>
      </div>
    </div>
  
      <script src="https://releases.transloadit.com/uppy/v2.2.3/uppy.min.js"></script>
      <script>
        var uppy = new Uppy.Core()
          .use(Uppy.Dashboard, {
            inline: true,
            proudlyDisplayPoweredByUppy:false,
            target: '#drag-drop-area',
            showProgressDetails: true,
            width: 1000,
          })
          .use(Uppy.XHRUpload, {
              endpoint: '{% url 'django_upload_url'  %}',
              headers: {'X-CSRFToken': " {{csrf_token}} "},
              formData: true,
              fieldName: "file",
              limit:1
          })
        uppy.on('complete', (result) => {
          console.log('Upload complete! We’ve uploaded these files:', result.successful)
          location.reload();
        })
      </script>
    </body>
  </html>
  

使用进度条在Django中上传多个文件 使用进度条在Django中上传多个文件

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接