带有验证和多个表单处理的 Django Ajax 提交

Posted

技术标签:

【中文标题】带有验证和多个表单处理的 Django Ajax 提交【英文标题】:Django Ajax Submission with validation and multiple forms handling 【发布时间】:2014-09-15 22:34:24 【问题描述】:

在 Django 管理界面中,有一个很好的功能,可以动态地将新项目添加到外键字段,我想使用 bootstrap modal 弹出窗口和 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);
  
);
);

PS:我知道它可能是重复的,但没有一个答案让我明白这一点。

【问题讨论】:

你总是可以实现 django admin 使用的类似方法,它实际上像你一样加载视图(例如添加一个类别)通过标记 is_popup 呈现模板,这反过来又删除了不需要加载的部分(侧边栏、标题等)。如果您以相同的方式实现(这并不难),那么您可以提交表单并由通常的 django 流程处理所有事情(表单验证、保存模型等)。 Django Admin 界面打开一个单独的弹出窗口,我想在同一页面中显示弹出窗口并在不刷新页面的情况下发送数据,以防止键入的数据丢失。 你可以修改它来生成一个modal而不是一个popup(modal其实就是一个popup...)。弹出窗口不会刷新页面也不会重定向您,它只会在您插入新条目时更新相关字段。 【参考方案1】:

ModelChoiceField 根据对象验证表单中的选择,如果它为空,则表单将不会验证。您可以通过使用 form.non_field_errors 和 field.errors 来调试它,以准确指出表单未得到验证的原因。

作为建议,当我有一个类似的用例时,我使用了 Dajax 和 Dajaxice,它们对我来说非常有效。我改用了 ChoiceFields,但它们甚至可以与 ModelChoiceFields 一起使用。

下面是 ChoiceField 和 Form Submission 的示例

【讨论】:

我找到了 Dajax 解决方案来解决我的问题,但他们说不建议使用它(couplig 工作人员)(github.com/jorgebastida/django-dajax/…)【参考方案2】:

这就是我过去的做法。请注意,这是一个非常精简的版本,并假定所有 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 并在选择列表中重新构建您的选项。

【讨论】:

感谢您的回答,我找到了一个基于相同想法的解决方案,稍后将详细发布。【参考方案3】:

在我为内联添加项目的相关类别所做的解决方案下方。

使用与问题相同的表格、网址并添加

添加分类的视图

@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 代码

我的解决方案中棘手的部分是将模态表单和 man 表单分隔在两个不同的 html 文件中,并使用 jQuery 处理新项目的添加和选择。

这个js代码必须包含在两个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');
                 
             
         );
     ); );

【讨论】:

以上是关于带有验证和多个表单处理的 Django Ajax 提交的主要内容,如果未能解决你的问题,请参考以下文章

有没有办法通过 ajax 提高正常的 Django 表单验证?

Django - 在同一个模板(ajax 和表单)中处理多个 CSRF 令牌禁止(CSRF 令牌丢失或不正确。)

如何构建 django ajax 模态弹出表单(带有服务器端表单)?

无需重定向的 Django 远程身份验证

django登录表单和表单验证在引导模式中使用ajax

带有ajax的Django表单,最好的方法是啥?