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)