user12314098
user12314098

Reputation:

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

This can easily be done with Ajax and Jquery, but this version of Django seems to be making it extra difficult. It requires the '{% csrf_token %}' (it'll throw an error without this) and that automatically submits the file when submit is pressed.

<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>

Here's the 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

So when I have preventDefault to stop Django from sending anything, but when I look at network, nothing is being sent and the "WOOOOO!" isn't being printed and my breakpoint in Django at the POST endpoint isn't be triggered. So I don't think the ajax is sending the file, but at the same time I'm getting no errors. Any advice?

Upvotes: 1

Views: 674

Answers (2)

user12314098
user12314098

Reputation:

Even though no error was thrown when I removed

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

it started to work so yea.

Upvotes: 1

Victor
Victor

Reputation: 2909

Pass e.currentTarget when instantiating a new FormData object so you include the csrf_token in the submitted info.

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

Upvotes: 0

Related Questions