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. ", 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)