如何使用Dropzone为多个图像字段上传Django中的多个图像

时间:2022-11-23 21:36:33

I am working on a project where the functionality is the user can upload his multiple images with a drag-n-drop feature. I am developing using the Django-python. I have implemented the functionality of drag-n-drop in django template, but I am getting error for images while submitting the form data.
My Html template code is :

我正在开发一个项目,其功能是用户可以使用拖放功能上传他的多个图像。我正在使用Django-python进行开发。我已经在django模板中实现了drag-n-drop的功能,但是在提交表单数据时我收到了图像错误。我的Html模板代码是:

<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 a dropzone.js for implementing the drag-drop-and sortable The error is coming as MultiValueDictKeyError at /saveNewUserInfo/, Exception Value: "'file'"
My Model is :

我正在使用dropzone.js来实现拖放和可排序错误来自/ saveNewUserInfo /的MultiValueDictKeyError,异常值:“'file'”我的模型是:

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 store the dropzone multiple images into these image fields. Appreciate for suggestions..

请建议如何将dropzone多个图像存储到这些图像字段中。欣赏建议..

2 个解决方案

#1


1  

I am glad that you have solved it. I have spent a few hours on this this is how I solved it:

我很高兴你解决了它。我已经花了几个小时这就是我解决它的方法:

The main issue with using dropzone is that as soon as files being droped in it, it will start to upload. So the images will not upload along with the rest of the form data.

使用dropzone的主要问题是,只要文件在其中下载,它就会开始上传。因此,图像不会与其余表单数据一起上传。

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

为了解决这个问题,我必须使用以下设置以编程方式创建dropzone对象:

$(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 exclude to forms.py (so that these fields will not show up in our template, we have dropzone to replace them):

我还将exclude添加到forms.py中(因此这些字段不会显示在我们的模板中,我们有dropzone来替换它们):

class CustomerInfoForm(forms.ModelForm):

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

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

上面的所有代码都是将每个带有图像的文本框中的数据一起提交到views.py中

Here is the views.py:

这是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 has been written to the record correctly.

我使用Django 1.8测试了这个解决方案,它的工作原理。我检查了数据库,并且路径已正确写入记录。

Now, to reflect upon this solution, it kind of defeated the purpose of using dropzone. Because users cannot upload the photos as soon as a file has been selected.

现在,为了反思这个解决方案,它有点打败了使用dropzone的目的。因为用户无法在选择文件后立即上传照片。

Since you have also solved this problem. Please post your solution and I am looking forward to learn something new from yours :)

既然你也解决了这个问题。请发布您的解决方案,我期待从您那里学到新的东西:)

#2


0  

Small upgrade on previous post overriding submit, I would like to add options:selected looping.

以前的帖子覆盖提交的小升级,我想添加选项:选择循环。

     $('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);
        }
    });

#1


1  

I am glad that you have solved it. I have spent a few hours on this this is how I solved it:

我很高兴你解决了它。我已经花了几个小时这就是我解决它的方法:

The main issue with using dropzone is that as soon as files being droped in it, it will start to upload. So the images will not upload along with the rest of the form data.

使用dropzone的主要问题是,只要文件在其中下载,它就会开始上传。因此,图像不会与其余表单数据一起上传。

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

为了解决这个问题,我必须使用以下设置以编程方式创建dropzone对象:

$(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 exclude to forms.py (so that these fields will not show up in our template, we have dropzone to replace them):

我还将exclude添加到forms.py中(因此这些字段不会显示在我们的模板中,我们有dropzone来替换它们):

class CustomerInfoForm(forms.ModelForm):

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

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

上面的所有代码都是将每个带有图像的文本框中的数据一起提交到views.py中

Here is the views.py:

这是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 has been written to the record correctly.

我使用Django 1.8测试了这个解决方案,它的工作原理。我检查了数据库,并且路径已正确写入记录。

Now, to reflect upon this solution, it kind of defeated the purpose of using dropzone. Because users cannot upload the photos as soon as a file has been selected.

现在,为了反思这个解决方案,它有点打败了使用dropzone的目的。因为用户无法在选择文件后立即上传照片。

Since you have also solved this problem. Please post your solution and I am looking forward to learn something new from yours :)

既然你也解决了这个问题。请发布您的解决方案,我期待从您那里学到新的东西:)

#2


0  

Small upgrade on previous post overriding submit, I would like to add options:selected looping.

以前的帖子覆盖提交的小升级,我想添加选项:选择循环。

     $('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);
        }
    });