File/Image 使用 Ajax 提交 Django 表单时字段未提交
File/Image field not submitting when using Ajax to submit Django form
我目前正在我的网站上创建一个自定义的管理页面,允许用户更新他们的个人资料页面。我有几个字段,包括个人资料图像的图像字段...然后我创建了一个 EditProfileForm 来处理此操作。我已经了解了如何在 Ajax 请求中将表单序列化到 post 表单数据到服务器端。我有这个适用于没有文件字段的其他表单,并且它工作得很好。但不知何故,它不适用于带有图像字段的这种形式。
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');
}
});
现在,在我处理这个 post 请求的视图中,我有...
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' 是 none。这是一个例子...
形式:
打印数据的结果...
所以即使我已经上传了图片,它还没有作为表单数据的一部分从 Ajax 请求中传递。我一直在研究但尚未找到有解决方案的类似问题。期待尽快得到你们这些好人的帮助。
我找到了解决办法!我使用 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)
这对我来说很管用...甜蜜又美好! :-)
我目前正在我的网站上创建一个自定义的管理页面,允许用户更新他们的个人资料页面。我有几个字段,包括个人资料图像的图像字段...然后我创建了一个 EditProfileForm 来处理此操作。我已经了解了如何在 Ajax 请求中将表单序列化到 post 表单数据到服务器端。我有这个适用于没有文件字段的其他表单,并且它工作得很好。但不知何故,它不适用于带有图像字段的这种形式。
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');
}
});
现在,在我处理这个 post 请求的视图中,我有...
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' 是 none。这是一个例子...
形式:
打印数据的结果...
所以即使我已经上传了图片,它还没有作为表单数据的一部分从 Ajax 请求中传递。我一直在研究但尚未找到有解决方案的类似问题。期待尽快得到你们这些好人的帮助。
我找到了解决办法!我使用 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)
这对我来说很管用...甜蜜又美好! :-)