1

I am trying to do a fairly common user requirement, allowing the user to upload multiple files in Django, and giving them the option to remove files that they may have accidentally uploaded.

As far as I can tell, even if the user remove the uploaded files from the DOM prior to the user submitting the form via Javascript code as shown here...Multiple file upload - with 'remove file' link, the uploaded files remain in the request.FILES.getlist(''). I have spent most of today researching this. I have in fact determined that when the uploaded files are deleted via Javascript from the DOM they are in fact still present in the request.FILES.getlist('').

I verified this by printing out the contents of the getlist file in my CreateView as shown below...

 list=[] #myfile is the key of a multi value dictionary, values are the uploaded files
 for f in request.FILES.getlist('files1'): #myfile is the name of your html file button
      filename = f.name
      print(filename)  

My question is how can I get the contents of the DOM and compare it to what's in request.FILES.getlist? I surmise that's how I'll be able to tell Django what's real and what's not. Thanks in advance for any thoughts.

Here's the Javascript code that I'm using...I documented it via a link above but here it is again for ease of reading. The Javascript seems to work just fine...it's just that the files are still in request.FILES.getlist. I suspect this is specific to Django/Python. Something additional needs to happen in order to reconcile the DOM with what actually remains in request.FILES.getlist.

  $(document).ready(function (){

  $.fn.fileUploader = function (filesToUpload) {
      this.closest(".files").change(function (evt) {

      for (var i = 0; i < evt.target.files.length; i++) {
          filesToUpload.push(evt.target.files[i]);
      };
      var output = [];

      for (var i = 0, f; f = evt.target.files[i]; i++) {
        var removeLink = "<a class=\"removeFile\" href=\"#\" data-fileid=\"" + i + "\">Remove</a>";

                output.push("<li><strong>", escape(f.name), "</strong> - ",
                    f.size, " bytes. &nbsp; &nbsp; ", removeLink, "</li> ");
            }

            $(this).children(".fileList")
                .append(output.join(""));
            });
      };

      var filesToUpload = [];

      $(document).on("click",".removeFile", function(e){
          e.preventDefault();
          console.log("Htell");
          var fileName = $(this).parent().children("strong").text();

          for(i = 0; i < filesToUpload.length; ++ i){
              if(filesToUpload[i].name == fileName){
                  filesToUpload.splice(i, 1);
              }
        }
          $(this).parent().remove();
      });

      $("#files1").fileUploader(filesToUpload);

    });

The HTML...

<div class="leftwidth22">
  <div class="width52">
    <h2 class="floatright23">Attachment(s) - </h2>
  </div>
</div>
  <div class="rightwidth60">
    <h2 class="width70">
      <div class="row files" id="files1">
          <span class="">
              <input type="file" name="files1" multiple />
          </span>
          <br />
          <ul class="fileList"></ul>
      </div>
    </h2>
  </div>

Here's my view as well...it's a CreateView...and most of the work is happening in POST...

def post(self, request, *args, **kwargs):
    if "cancel" in request.POST:
        return HttpResponseRedirect(reverse('Procedures:procedure_main_menu'))
    else:
        self.object = None
        user = request.user
        form_class = self.get_form_class()
        form = self.get_form(form_class)
        file_form = NewProcedureFilesForm(request.POST, request.FILES)
        files = request.FILES.getlist('files1') #field name in model
        if form.is_valid() and file_form.is_valid():
            procedure_instance = form.save(commit=False)
            procedure_instance.user = user
            procedure_instance.save()
            list=[] #myfile is the key of a multi value dictionary, values are the uploaded files
            for f in request.FILES.getlist('files1'): #myfile is the name of your html file button
                filename = f.name
                print(filename)
            for f in files:
                procedure_file_instance = NewProcedureFiles(attachments=f, new_procedure=procedure_instance)
                procedure_file_instance.save()
            return self.form_valid(form)
        else:
            form_class = self.get_form_class()
            form = self.get_form(form_class)
            file_form = NewProcedureFilesForm()
            return self.form_invalid(form)
Steve Smith
  • 1,019
  • 3
  • 16
  • 38
  • I've included the link...in the description with the Javascript that I'm using. I've verified that it works in so much that it does remove the uploaded files from the DOM and the messages are reflected properly when the user clicks on REMOVE. – Steve Smith Sep 16 '21 at 23:53
  • Yep. To the letter. What do you mean it doesn't send anything to the server? In the even that a multiple files are uploaded it works fine. It's when the remove happens...the screen is updated to say the files are removed...they are removed from the DOM as well...but the file count remains and the files themselves still get uploaded upon submission. I'll add in the corresponding HTML as well. – Steve Smith Sep 17 '21 at 00:16
  • Agree the uploadBtn has no functionality. Here's what I think is happening...Basically Django ignores the Javascript the Javascript is basically only producing a list of files that are uploaded...along with their stats....The files get automatically uploaded the second you click on attach files. Those files are then immediately put into the request.FILES file. The upload happens entirely via Django and the CreateView and ModelForm. Javascript is not handling the upload, Django is. So the Javascript is really only serving as a false front end...to list out the files...with a remove link. – Steve Smith Sep 17 '21 at 02:18
  • The remove link does in fact remove the files from the DOM...that works...the problem is that Django ignores all of that and uploads the files upon the Choose FIles click. Then Django knows what the files are and puts them into the Request.FILES file. The problem is when the Javascript to remove a file is executed...it removes the file from the DOM as expected...but Django still has those files and uploads them. I'm trying to figure out now how to reconcile the DOM with the Request.FILES entries at the time of the form submission. Hopefully this helps to explain what I've found so far. – Steve Smith Sep 17 '21 at 02:21

0 Answers0