Django Ajax提交与验证及多个表单处理
在Django的管理界面中,有一个很棒的功能,可以动态地向外键字段添加新项目。我想用Bootstrap的弹窗和Ajax来实现类似的功能,用于提交和验证表单。
这是我的使用场景:
这是添加项目的主表单。项目有一个引用和一个类别。
这是添加新类别的第二个表单。
我在显示弹窗和提交表单以添加新类别方面没有问题。问题在于表单验证(如果用户提交了空表单)以及如何刷新选择框的内容,以便添加新类别。
这是我的代码:
forms.py
class ItemForm(forms.ModelForm):
ref = forms.CharField(widget=forms.TextInput(attrs={'class':'form-control'}),max_length=255)
category = forms.ModelChoiceField(queryset=ItemCategory.objects.all(), empty_label="(choose from the list)")
class ItemCategoryForm(forms.ModelForm):
category = forms.CharField(
max_length=255,
required=True,
help_text='Add a new category')
views.py
def add(request):
if request.method == 'POST':
form = ItemForm(request.POST)
if form.is_valid():
item= Item()
item.ref = form.cleaned_data.get('ref')
item.save()
return redirect('/item_list/')
else:
form = ItemForm()
form1 = ItemCategoryForm()
return render(request, 'item/add.html', {'form': form, 'form1':form1})
def add_category(request):
if request.method == 'POST':
form1 = ItemCategoryForm(request.POST)
if form1.is_valid():
vulnCategory = ItemCategory()
ItemCategory.category = form1.cleaned_data.get('category')
ItemCategory.save()
if request.is_ajax():
#TODO: What Should I redirect
else:
#TODO: What Should I redirect
else:
#TODO: What Sould I do to return errors without reloding the page and to refresh the list of categories
urls.py
url(r'^add/$', 'add', name='add'),
url(r'^add_category/$', 'add_category', name='add_category'),
我还添加了这个jQuery函数来加载结果。
$(".add").click(function () {
$.ajax({
url: '/items/add_category/',
data: $("form").serialize(),
cache: false,
type: 'post',
beforeSend: function () {
$("#add_category .modal-body").html("<div style='text-align: center; padding-top: 1em'><img src='/static/img/loading.gif'></div>");
},
success: function (data) {
$("#add_category .modal-body").html(data);
}
});
});
附言:我知道这可能是重复的,但没有一个答案能让我明白问题所在。
3 个回答
ModelChoiceField这个东西是用来检查表单里选择的内容是否有效的。如果你没有选择任何东西,表单就会不通过验证。你可以通过使用{{ form.non_field_errors }}和{{ field.errors }}来调试,这样可以清楚地看到表单为什么不通过验证。
我有个类似的情况时,使用了Dajax和Dajaxice,它们对我来说效果很好。我用的是ChoiceFields,但即使是ModelChoiceFields也能正常工作。
这里有一个关于ChoiceField和表单提交的例子。
这是我过去处理这个问题的方法。请注意,这只是一个非常简化的版本,假设所有的请求都是通过ajax来完成的,目的是让你了解可以怎么做。你可以在这个基础上进行扩展。
if form.is_valid():
do_form_work()
# Compile a list of lists (or tuples) of the categories
# e.g. [[x.pk, x.name] for x in categories]
categories = get_categories()
json = json.dumps(categories)
return HttpRepsonse(json, {'content_type' : 'application/json'})
else:
# 'template' here is a partial template of just the form
render(self.request, template, context, status=500)
如果表单不合法,你可以在ajax提交时使用'error'方法来捕捉500错误代码,然后重新显示表单,并把所有的错误信息展示出来。这样用户就可以在弹窗里修改错误的地方。
如果表单合法,你可以拿到返回的json数据,然后重新构建下拉列表中的选项。
下面是我为一个项目在线添加相关分类所做的解决方案。
我使用了和问题中相同的表单和网址,并进行了添加。
添加分类的视图
@login_required
def add_category(request):
data = {}
if request.method == 'POST' :
form = ItemCategoryForm(request.POST)
if form.is_valid():
itemCategory= ItemCategory()
itemCategory.name = form.cleaned_data.get('name')
itemCategory.save()
data['new_itemcategory_value'] = itemCategory.name;
data['new_itemcategory_key'] = itemCategory.pk;
data['stat'] = "ok";
return HttpResponse(json.dumps(data), mimetype="application/json")
else:
data['stat'] = "error";
return render(request, 'item/add_category_modal.html', {'form': form})
else:
form = ItemCategoryForm()
return render(request, 'item/add_category_modal.html', {'form': form})
JavaScript代码
我解决方案中比较棘手的部分是把模态框和主表单分成两个不同的HTML文件,并使用jQuery来处理新项目的添加和选择。
这段JavaScript代码需要包含在这两个HTML文件中:
// This function is for showing the modal
$(function () {
$(".add_category_show_button").click(function () {
$.ajax({
type: 'GET',
url: '/item/add_category/',
data: $("form").serialize(),
cache: false,
success: function (data, status) {
$('#add_category_modal_id').html(data);
$('#add_category_modal_id').modal()
}
});
}); });
// This second function is for submitting the form inside the modal and handling validation
$(function () {
$(".add_category_submit_button").click(function () {
$.ajax({
type: 'POST',
url: '/item/add_category/',
data: $("form").serialize(),
cache: false,
success: function (data, status) {
if (data['stat'] == "ok") {
$('#add_category_modal_id').modal('hide');
$('#add_category_modal_id').children().remove();
$('#id_category')
.append($("<option></option>")
.attr("value", data['new_itemcategory_key'])
.text(data['new_itemcategory_value']))
.val(data['new_itemcategory_key']);
}
else {
$('#add_category_modal_id').html(data);
$('#add_category_modal_id').modal('show');
}
}
});
}); });