Django Ajax提交与验证及多个表单处理

8 投票
3 回答
17238 浏览
提问于 2025-04-18 14:35

在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 个回答

1

ModelChoiceField这个东西是用来检查表单里选择的内容是否有效的。如果你没有选择任何东西,表单就会不通过验证。你可以通过使用{{ form.non_field_errors }}和{{ field.errors }}来调试,这样可以清楚地看到表单为什么不通过验证。

我有个类似的情况时,使用了Dajax和Dajaxice,它们对我来说效果很好。我用的是ChoiceFields,但即使是ModelChoiceFields也能正常工作。

这里有一个关于ChoiceField表单提交的例子。

3

这是我过去处理这个问题的方法。请注意,这只是一个非常简化的版本,假设所有的请求都是通过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数据,然后重新构建下拉列表中的选项。

9

下面是我为一个项目在线添加相关分类所做的解决方案。

我使用了和问题中相同的表单和网址,并进行了添加。

添加分类的视图

@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');
                 }
             }
         });
     }); });

撰写回答