我正在开发一个项目,其功能是用户可以使用拖放功能上传他的多个图像。我正在使用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>
我正在使用dropzone.js来实现拖放和可排序
错误发生在MultiValueDictKeyError at /saveNewUserInfo/, Exception Value: "'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
请建议如何将dropzone多个图像存储到这些图像字段中。感谢建议..
答案 0 :(得分:1)
我很高兴你解决了它。我已经花了几个小时来解决这个问题:
使用dropzone的主要问题是,只要文件在其中下载,它就会开始上传。因此,图像不会与其他表单数据一起上传。
为了解决这个问题,我必须使用以下设置以编程方式创建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
});
});
这是模板文件:
<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>
我还在 forms.py 中添加了排除项(因此这些字段不会显示在我们的模板中,我们有dropzone来替换它们):
class CustomerInfoForm(forms.ModelForm):
class Meta:
model = CustomerProfile
exclude=('user_image1','user_image2','user_image3','user_image4','user_image5')
上面的所有代码都是将每个带有图片的文本框中的数据一起提交到您的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)
我使用Django 1.8测试了这个解决方案并且它可以工作。我检查了数据库,并且路径已正确写入记录。
现在,为了反思这个解决方案,它有点打败了使用dropzone的目的。因为用户无法在选择文件后立即上传照片。
既然你也解决了这个问题。请发布您的解决方案,我期待从您那里学到新东西:)
答案 1 :(得分:0)
以前的帖子覆盖提交的小升级,我想添加options:selected
循环。
$('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);
}
});