【问题标题】:MultiValueDictKeyError when trying to upload image in Django尝试在 Django 中上传图像时出现 MultiValueDictKeyError
【发布时间】:2018-04-01 01:11:18
【问题描述】:

您好,我正在尝试使用 Django 通过表单字段上传图像文件,但在尝试提交表单时出现 django.utils.datastructures.MultiValueDictKeyError。

这是我的forms.py:

class UserProfileForm(forms.ModelForm):
    type = forms.ModelChoiceField(queryset=UserType.objects.all(), required=True)
    phone = forms.CharField(required=False)
    address = forms.CharField(required=False)
    picture = forms.ImageField(required=False)
    class Meta:
        model = UserProfile # matches data model
        fields = ('type','phone','address','picture') # shown on the form

这是我的models.py:

class UserProfile(models.Model):
    user = models.OneToOneField(User)
    type = models.ForeignKey(UserType, on_delete=models.CASCADE)
    phone = models.CharField(max_length=10, blank=True)
    address = models.CharField(max_length=128, blank=True)
    picture = models.ImageField(upload_to='profile_images', blank=True)
    def __str__(self):
        return self.user.username

这是我的views.py:

def register(request):
    if request.method == 'POST':
        response = {}

        username = request.POST.get('username')
        password1 = request.POST.get('password1')
        password2 = request.POST.get('password2')
        type = request.POST.get('type')
        first_name = request.POST.get('first_name')
        last_name = request.POST.get('last_name')
        email = request.POST.get('email')
        phone = request.POST.get('phone')
        address = request.POST.get('address')
        picture = request.POST.get('picture')

        data = {'username': username,
                'password1': password1,
                'password2': password2,
                'type': UserType.objects.get(type=type).pk,
                'first_name': first_name,
                'last_name': last_name,
                'email': email,
                'phone': phone,
                'address': address,
                'picture': picture}
        user_form = UserForm(data)
        profile_form = UserProfileForm(data)

        if user_form.is_valid() and profile_form.is_valid():
            user = user_form.save()
            user.set_password(data['password1'])
            user.save()
            profile = profile_form.save(commit=False)
            profile.user = user
            #if 'picture' in request.FILES:
                #profile.picture = request.FILES['picture']
            #picture = Image.open(StringIO(profile_form.cleaned_data['picture'].read()))
            #picture.save(MEDIA_DIR, "PNG")
            #newPic = Pic(imgfile=request.FILES['picture'])
            newPic=request.FILES['picture']
            newPic.save()
            profile.save()
            return JsonResponse({'response': 'success'})
        else:
            errors =  user_form.errors.copy()
            errors.update(profile_form.errors)
            return JsonResponse({'response': errors})

这是我的 HTML 表单:

<form class="uk-form-horizontal uk-margin-small" id="registration_form" 
            method="post" action="{% url 'register' %}" enctype="multipart/form-data">

        <div class="uk-margin">
                <label class="uk-form-label" for="form-horizontal-text">Profile photo</label>
                <div class="uk-form-controls">
                    <div class="uk-width-1-1" uk-form-custom="target: true">
                        <input name="picture" id="id_picture" type="file">
                        <input class="uk-input" type="text" placeholder="Select file" disabled>
                    </div>
                </div>
            </div>

        <div class="uk-margin-top">
                        <button class="uk-button uk-button-primary uk-width-1-1" type="submit" value="Submit" />Register</button>
                    </div>
                </div>
            </div>  

 </form>    

我正在尝试在 AJAX 函数中传递注册表单的值:

$(document).on('submit','#registration_form',function(e){
    e.preventDefault();

    //if (password_match){
        $.ajax({
            type:'POST',
            url: "{% url 'register' %}",
            data:{
                username: $('#id_reg_username').val(),
                password1: $('#id_password1').val(),
                password2: $('#id_password2').val(),
                type: $('#id_user_type').val(),
                first_name: $('#id_first_name').val(),
                last_name: $('#id_last_name').val(),
                email: $('#id_email').val(),
                phone: $('#id_phone').val(),
                address: $('#id_address').val(),
                //PICTURE UPLOAD HERE?
                picture: $('#id_picture').val(),
                csrfmiddlewaretoken:$('input[name=csrfmiddlewaretoken]').val()  

我在这里尝试了谷歌搜索和其他解决方案,我无法让它接受并保存图像,有人可以帮忙吗?

【问题讨论】:

  • 所以 a) 这不是我能找到的任何搜索的完全欺骗,而是文档中很好地涵盖的主题。 b) 以实例化表单的方式从request.POST 中提取值是不寻常的。 c) 文件进入request.FILES 而不是request.POST - 但您可能还有其他问题。基本上,复习docs.djangoproject.com/en/1.11/topics/http/file-uploads
  • 在将 picture = request.POST.get('picture') 更改为 picture=request.FILES.get('picture') 后,我得到一个 'NoneType' 对象没有属性保存在 views.py 中并尝试将所有 ImageFields 更改为 FileFields.. :(
  • 您正在尝试通过 AJAX 上传文件,这有点棘手 - 仅传递 $('#id_picture').val() 将不起作用。如何实现AJAX文件上传,见this question

标签: python html mysql django


【解决方案1】:

form 元素中的属性应该是 enctype,而不是 encrypt。

<form method="post" enctype="multipart/form-data"></form>

【讨论】:

【解决方案2】:

您可以使用 request.dataget() 方法来提取传入的值,像这样

    def create(self, request, *args, **kwargs):
    course_owner = User.objects.get(email=request.auth.get('user_id'))
    image = request.data.get('image')
    video = request.data.get('video')
    image_upload = cloudinary.uploader.upload(image)
    video_upload = cloudinary.uploader.upload(video)
    request.data['course_owner'] = course_owner.id
    request.data['image'] = image_upload.get('url')
    request.data['video'] = video_upload.get('url')
    serialized = CourseModelSerializer(data=request.data)

【讨论】:

    【解决方案3】:

    当您提供输入文件字段并且用户提交表单而不上传任何照片时,也会发生这种情况。特别是如果您没有设置输入文件所需的属性。

    您需要在视图中编写一个函数来测试照片是否已上传!

    【讨论】:

      【解决方案4】:

      请改用FILES。例如:photo = request.FILES['photo']

      【讨论】:

        最近更新 更多