【问题标题】:File/Image field not submitting when using Ajax to submit Django form使用 Ajax 提交 Django 表单时文件/图像字段未提交
【发布时间】:2021-09-30 04:00:03
【问题描述】:

我目前正在我的网站上创建一个自定义管理页面,用户可以在其中更新他们的个人资料页面。我有几个字段,包括个人资料图像的图像字段...然后我创建了一个 EditProfileForm 来处理此操作。我已经了解了如何在 Ajax 请求中序列化表单以将表单数据发布到服务器端。我有这个适用于其他没有文件字段的表单,它工作得很好。但不知何故,它只是不适用于带有图像字段的表单。

forms.py

class EditProfileForm(forms.Form):
    avatar = forms.ImageField(widget=forms.ClearableFileInput(attrs=edit_profile_form_fields['avatar']), label='Change Profile Image')
    mobile = forms.CharField(widget=forms.TextInput(attrs=edit_profile_form_fields['mobile']), label='Mobile Number', required=False)
    street = forms.CharField(widget=forms.TextInput(attrs=edit_profile_form_fields['street']), label='Street', required=False)
    city = forms.CharField(widget=forms.TextInput(attrs=edit_profile_form_fields['city']), label='City', required=False)
    state = forms.CharField(widget=forms.TextInput(attrs=edit_profile_form_fields['state']), label='State', required=False)
    country = forms.CharField(widget=forms.TextInput(attrs=edit_profile_form_fields['country']), label='Country', required=False)
    about = forms.CharField(widget=forms.Textarea(attrs=edit_profile_form_fields['about']), label='About Me', required=False)


    def clean_mobile(self):
        if Account.objects.filter(mobile=self.cleaned_data['mobile']).exists() and len(self.cleaned_data['mobile']) > 0:
            raise forms.ValidationError('Mobile already exists!')

        return self.cleaned_data['mobile']

    def save(self, user_id):
        account = Account.objects.get(user_id=user_id)

        account.avatar = self.cleaned_data['avatar']
        account.mobile = self.cleaned_data['mobile']
        account.street = self.cleaned_data['street']
        account.city = self.cleaned_data['city']
        account.state = self.cleaned_data['state']
        account.country = self.cleaned_data['country']
        account.about = self.cleaned_data['about']
        account.save()

在我的 html 中,我有...

<form id="edit-profile-form" enctype="multipart/form-data">
    {% csrf_token %}
    <div class="form-group">
        <label for="avatar">
            {{ edit_profile_form.avatar.label }}
        </label>
        {{ edit_profile_form.avatar }}
     </div>

     <div class="form-group">
         <label for="mobile">
             {{ edit_profile_form.mobile.label }}
             <span class="mobile-exist text-danger" style="display: none;"></span>
         </label>
         {{ edit_profile_form.mobile }}
     </div>

     <div class="form-group">
         <label for="street">
             {{ edit_profile_form.street.label }}
         </label>
         {{ edit_profile_form.street }}
     </div>

     <div class="form-group">
         <label for="city">
             {{ edit_profile_form.city.label }}
         </label>
         {{ edit_profile_form.city }}
     </div>

     <div class="form-group">
         <label for="country">
             {{ edit_profile_form.country.label }}
         </label>
         {{ edit_profile_form.country }}
     </div>

     <div class="form-group">
         <label for="about">
             {{ edit_profile_form.about.label }}
         </label>
         {{ edit_profile_form.about }}
     </div>

     <div class="d-flex align-items-center">
         <button type="submit" class="btn btn-outline-warning px-3" id="edit-profile-submit-btn">
              Update Profile <span class="btn-icon-right"><i class="fa fa-save"></i></span>
         </button>

         <button type="reset" class="btn btn-outline-primary px-3 ml-3" id="edit-profile-reset-btn">
              Reset <span class="btn-icon-right"><i class="fa fa-refresh"></i></span>
         </button>

         <button type="button" class="btn btn-outline-danger px-3 ml-3" id="edit-profile-div-close">
              Cancel <span class="btn-icon-right"><i class="fa fa-times"></i></span>
         </button>
     </div>
</form>

在我进行 Ajax 调用的 js 中,我有...

 var csrfmiddlewaretoken = $("#edit-profile-form").find("input[name='csrfmiddlewaretoken']").val();
 var form_data = $('#edit-profile-form').serialize();

 $.ajax({
     type: 'POST',
     url: '/edit-profile/',
     dataType : "json",
     data : {
         csrfmiddlewaretoken: csrfmiddlewaretoken,
         form_data: form_data,
     },
     
     success: function (data){
         console.log('Success');
     },

     error: function (){
         console.log('Error');
     }
 });

现在在我处理此发布请求的视图中,我有...

class EditProfileView(LoginRequiredMixin, TemplateView):
    template_name = 'dashboard/pages/profile.html'
    form_class = EditProfileForm

    def post(self, request, *args, **kwargs):
        from django.http import QueryDict  #To basically de-serialize the serialized form passed by the Ajax request

        new_form_data = QueryDict(request.POST['form_data'].encode('ASCII'))

        #From the new form data (QueryDict Obj), I will set a dict.
        data = {
            'avatar': new_form_data.get('avatar'),
            'mobile': new_form_data.get('mobile'),
            'street': new_form_data.get('street'),
            'city': new_form_data.get('city'),
            'state': new_form_data.get('state'),
            'country': new_form_data.get('country'),
            'about': new_form_data.get('about'),
        }

        #Passing data dict as an argument to initialize the form
        form = self.form_class(data)

        if form.is_valid():
            print('Form is valid')

        else:
            print('Form is not valid')

我已尝试打印我创建的 data 字典,但 'avatar' 没有。这是一个例子......

形式:

打印数据的结果...

因此,即使我已经上传了图像,它也没有作为 Ajax 请求的表单数据的一部分传递。我一直在研究,但还没有找到有解决方案的类似问题。期待很快能从你们这些优秀的人那里得到一些帮助。

【问题讨论】:

标签: jquery django ajax post django-forms


【解决方案1】:

我找到了解决办法!我使用FormData 将我的编辑配置文件表单中的数据打包,然后将图像字段 附加到FormData 然后提交。提交的方法与我在处理无文件时使用的方法有点不同。

在我的 js 中更新...

var form = $("#edit-profile-form")[0];
var form_data = new FormData(form);

// Appending the attached file to the form_data to access it from the server side
form_data.append('new_avatar', $("#avatar")[0].files[0]);

$.ajax({
    type: 'POST',
    url: '/edit-profile/',
    data: form_data,
    cache: false,
    processData: false,
    contentType: false,

    success: function (data){
        console.log('Success');
    },

    error: function (){
       console.log('Error');
    }
});

那么在我看来,我只会以正常方式初始化表单,而不进行任何反序列化。

    def post(self, request, *args, **kwargs):
        context = {}
        form = self.form_class(data=request.POST, files=request.FILES)

        if form.is_valid():
            print('Form is valid')

        else:
            print('Form is not valid')

        return JsonResponse(context)

这为我完成了工作......甜蜜而美好! :-)

【讨论】:

    猜你喜欢
    • 2017-07-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-03-19
    • 2019-03-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多