How to upload multiple images to Django using Dropzone for multiple image fields

I am working on a project in which the userโ€™s functionality allows him to upload multiple images using the drag-n-drop function. I am developing Django-python. I implemented drag-n-drop functionality in a django template, but I get an error for images when submitting form data.
My HTML template code is:

<form id="newUserForm" name="newUserForm" data-abide action="{% url 'saveNewUserInfo'%}" method="post" enctype="multipart/form-data"> {% csrf_token %} <div class="section"></div> some input fields <!-- The div for uploading the images --> <div class="dropzone" style="border: 1px solid red;"></div> <input type="submit" value="save"> </form> 

I am using dropzone.js to implement drag-drop-and sortable. The error appears as MultiValueDictKeyError at /saveNewUserInfo/, Exception Value: "'file'"
My model:

 class CustomerProfile(models.Model): customer_id = models.CharField(db_column='customer_id', primary_key=True, max_length=20) first_name = models.CharField(db_column='first_name', max_length=30, blank=True, null=True) last_name = models.CharField(db_column='last_name', max_length=30,blank=True,null=True) user_name = models.CharField(db_column='user_name', max_length=50,unique=True) phone_number = models.CharField(db_column='phone_number', max_length=15,blank=True,null=True) email_id = models.EmailField(db_column='email_id', max_length=50,blank=True, null=True) user_image1 = models.ImageField(upload_to=IMAGES_PATH, db_column='user_image1', max_length=100) user_image2 = models.ImageField(upload_to=IMAGES_PATH, db_column='user_image2', max_length=100) user_image3 = models.ImageField(upload_to=IMAGES_PATH, db_column='user_image3', max_length=100) user_image4 = models.ImageField(upload_to=IMAGES_PATH, db_column='user_image4', max_length=100) user_image5 = models.ImageField(upload_to=IMAGES_PATH, db_column='user_image5', max_length=100) 

forms.py

 class CustomerInfoForm(forms.ModelForm): class Meta: model = CustomerProfile 

Please suggest how to save multiple Dropzone images in these image fields. Appreciate for suggestions ..

+5
source share
2 answers

I'm glad you decided that. I spent several hours on it, so I solved it:

The main problem with using dropzone is that as soon as the files are uploaded, it will start loading. Thus, images will not be loaded with the rest of the form data.

To handle this, I had to create a dropzone object programmatically with the following settings:

 $(document).ready(function(){ var list_of_files = new Array(); Dropzone.autoDiscover = false; //prevent dropzone to automatically discover the dropzone object in your html $("div#dropzone").dropzone({ uploadMultiple: true, // allow multiple upload autoProcessQueue: false, // prevent dropzone from uploading automatically url: "/", //dropzone needs a url attribute or it complains, what value you put here does not really matter. It is only purpose is to prevent a javascript error message from chrome console maxFiles: 5, //set max uploads to 5 since you only have 5 image files in your model init: function(){ //everytime a file is uploaded, save the file object //for later use this.on("addedfile", function(file) { if (list_of_files.length < 5) { list_of_files.push(file) console.log("file added"); } }); } }); // the following function override the "submit" button in the form $(document).on("click", "button", function(e){ e.preventDefault() //prevent the form from submitting console.log('num of files: ' + list_of_files.length); var formData = new FormData(); // construct our own upload data var inputs = $("#newUserForm input"); //get all of the data from textboxes $.each(inputs, function(obj, v){ var name = $(v).attr("name") var val = $(v).val(); console.log('name: ' + name + ' value: ' + val); formData.append(name, val); }); //get the file object from dropzone and put it into our formdata for(i=0;i<list_of_files.length;i++) { formData.append('user_image'+(i+1), list_of_files[i]); } var request = new XMLHttpRequest(); request.open("POST", "/"); //config your post url here request.send(formData); //send the post request to server }); }); 

Here is the template file:

 <form id="newUserForm" name="newUserForm" method="post" enctype="multipart/form-data"> {% csrf_token %} {% if form %} {% for field in form %} <p>{{ field.label_tag }} {{ field }}</p> {% endfor %} {% endif %} <!-- The div for uploading the images --> <div id="dropzone" class="dropzone"></div> <button id='save'> save </button> </form> 

I also added an exception to forms.py (so that these fields do not appear in our template, we have dropzone to replace them):

 class CustomerInfoForm(forms.ModelForm): class Meta: model = CustomerProfile exclude=('user_image1','user_image2','user_image3','user_image4','user_image5') 

All of the code above is to send data from each text box with images of your .py views together in one step

Here are views.py :

 def index(request): if request.method == 'POST': form = CustomerInfoForm(request.POST) if (form.is_valid()): instance = form.save(commit=False) #request.FILES contains all of the uploaded images #key is 'user_image1', 'user_image2', value is the image file in memory for key, value in request.FILES.iteritems(): a_path = '/a/b' save_uploadfile_to_disk(a_path, file) setattr(instance, key, a_path) //I made up the path here form.save() //save the form for real #do not forget to return a response else: print form.errors #for debugging only else: form = CustomerInfoForm() context = {'form': form} return render(request, 'test_dropzone/index.html', context) def save_uploadfile_to_disk(full_path, file): with open(full_path, 'w+') as destination: for chunk in file.chunks(): destination.write(chunk) 

I tested this solution using Django 1.8 and it works. I checked the database and the path was correctly written to the record.

Now, to reflect on this decision, he defeated the goal of using dropzone. Since users can not upload photos immediately after selecting a file.

Since you also solved this problem. Please post your decision, and I look forward to learning something new from you :)

+1
source

A small update in the previous post overriding submit, I would like to add an options:selected loop.

  $('option:selected').each(function(){ var name = $(this).parent().attr('name') if ($(this).val()) { var val = $(this).val() console.log('name: ' + name + ' value: ' + val); formData.append(name, val); } else { var val = "" console.log('name: ' + name + ' value: ' + val); formData.append(name, val); } }); 
0
source

Source: https://habr.com/ru/post/1213782/


All Articles