如何在 Django 3.0.4 中上传文件时有进度条

How to have a progress bar with uploading a file in Django 3.0.4

使用 Ajax 和 Jquery 可以很容易地做到这一点,但是这个版本的 Django 似乎使它变得格外困难。它需要'{% csrf_token %}'(没有它会抛出错误)并且在按下提交时自动提交文件。

<form
  id="data_upload"
  method="POST"
  enctype="multipart/form-data"
  class="form-horizontal"
>
  {% csrf_token %}
  <div class="input-group mb-3">
    <div class="custom-file">
      <input
        id="file_select"
        type="file"
        class="custom-file-input"
        id="inputGroupFile02"
        accept=".csv, .xslx"
        name="file"
      />
      <label
        id="submit_label"
        class="custom-file-label"
        for="inputGroupFile02"
        aria-describedby="inputGroupFileAddon02"
        >Upload CSV or Excel file</label
      >
    </div>
    <div class="input-group-append">
      <button
        id="upload_button"
        type="submit"
        class="input-group-text btn"
        id="inputGroupFileAddon02"
        disabled
      >
        Upload
      </button>
    </div>
  </div>
  <div class="d-flex justify-content-center">
    <div
      id="loading_div"
      class="spinner-border"
      role="status"
      style="display: none;"
    >
      <span class="sr-only">Loading...</span>
    </div>
  </div>
</form>

这是ajax

  $(document).ready(function () {
    $("#data_upload").submit(function (event) {
      event.preventDefault();
      var fd = new FormData
      fd.append('file', file_input[0].files[0])

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

          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,
        type: "POST",
        data: fd,
        processData: false,
        contentType: false,
        success: function (result) {
          alert('WOOOO!')
        },
      });
    });
  });

urls.py

urlpatterns = [
    path('upload', UploadView.as_view(), name="upload"),
]

View.py

class UploadView(TemplateView):
    def get(self, request, *args, **kwargs):
        return render(request, 'upload_datatable.html')

    def post(self, request, *args, **kwargs):
        uploaded_file = request.FILES['file']
        uploaded_file_name = uploaded_file.name

        if len(uploaded_file) != 0:
            if uploaded_file_name.endswith('.csv'):
                file_path = self.upload_csv_to_data(uploaded_file)
            elif uploaded_file_name.endswith('xlsx'):
                file_path = self.upload_excel(uploaded_file)
            else:
                return HttpResponse({'error': 'Not valid CSV or Excel'}, content_type="application/json",
                                    status_code=400)
        else:
            return HttpResponse({'error': 'No Data'}, content_type="application/json", status_code=400)

    def upload_csv_to_data(self, file):
        id = str(uuid.uuid4())
        with open(f'data/{id}.csv', 'wb+') as destination:
            for chunk in file.chunks():
                destination.write(chunk)

        return f'data/{id}'

    def upload_excel_to_data(self, file):
        id = str(uuid.uuid4())
        with open(f'data/{id}.txt', 'wb+') as destination:
            for chunk in file.chunks():
                destination.write(chunk)

        return f'data/{id}'

    def is_csv_file(self, file):
        try:
            dialect = csv.Sniffer().sniff(file.read(1024))
            file.seek(0)

            return True
        except csv.Error:
            return False

    def is_excel_file(self, file):
        try:
            book = open_workbook(file)

            return True
        except XLRDError as e:
            return False

因此,当我使用 preventDefault 来阻止 Django 发送任何内容时,但是当我查看网络时,没有任何内容被发送并且 "WOOOOO!" 没有被打印并且我在 Django 中的断点位于 POST 端点未被触发。所以我不认为 ajax 正在发送文件,但同时我没有收到任何错误。有什么建议吗?

在实例化新的 FormData 对象时传递 e.currentTarget,以便在提交的信息中包含 csrf_token

...
var fd = new FormData(event.currentTarget)
fd.append('file', file_input[0].files[0])
...

即使我删除时没有抛出错误

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

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

      return xhr;
    },

它开始工作了,是的。