在Django中动态添加表单到formset并使用AJAX提交

时间:2015-08-06 15:06:42

标签: ajax django django-forms

我已经阅读了很多关于如何在Django中动态添加表单到模型formset的答案,并且可以成功地实现它。但是,我现在想用AJAX提交formset。这主要是现在工作,但我有一个问题,我无法在任何其他答案中找到解决方案:

如果您动态地向表单集添加表单,则为其提供一个新的表单ID号,该表单号大于当前表单的最大值,并且还将管理TOTAL_FORMS计数增加1。然后,新添加的表单将成功保存为新对象。

我正在尝试通过AJAX提交,以便用户可以继续编辑而无需刷新页面。 formset保存得很好,但任何动态添加的表单现在都是现有对象。为了解决这个问题,我需要在保存成功时增加管理表单上的INITIAL_FORMS计数。很容易。但是,我也意识到我需要为新创建的对象提供一个ID,因为它们现在存在于数据库中。

如何让我的视图在响应AJAX调用时告诉我新对象的ID?或者有更好的方式来看待这个吗?

2 个答案:

答案 0 :(得分:1)

Django表单和表单集用于基于浏览器的经典数据发布。虽然它们绝对可以与Javascript一起使用,但是你想要从正常行为中分离的越多,它就越复杂。

根据您的要求,您可能会开始考虑删除它并切换到Javascript + REST端点。当然,如果您需要渐进式增强功能,并且您需要在没有javascript的情况下使用它,那么这不是一个选项。

在任何情况下,您都希望有一个自定义视图,以便从JS发布,以便您可以返回结果并在AJAX处理程序中轻松解析它。可能是一些JSON。

您可以采取多种方法。

  • 让您的AJAX将数据发送到其他网址。如果您有API或计划在某个时刻构建一个API,这是相关的。因此,您的表单在正常提交时将执行旧式处理,但您的AJAX将与API端点通信。

    例如,您的表单发送到https://example.com/myform,但您的Javascript代码会在https://example.com/api/v1/mymodel/与REST API进行通信(根据需要发送PUT,POST和DELETE请求)。

  • 或者,如果你没有API并且构建一个似乎有点过分,你可能只是改变你的视图,因此它根据数据是以常规方式提交还是使用AJAX来不同地格式化其输出。 / p>

    你会这样做:

    class MyFormView(.....):
        def render_to_response(self, context, **kwargs):
            if self.request.is_ajax():
                return self.render_to_json(context, **kwargs)
            return super().render_to_response(context, **kwargs)
    
        def render_to_json(context, **kwargs):
            data = {
                # see below!
            }
            return HttpResponse(
                content=json.dumps(data).encode('ascii'),
                content_type='application/json',
            )
    

    这只是一个大纲。您需要确保is_ajax能够正确检测到它(请参阅django doc)。您需要从data正确构建context:将要发送回JS代码的内容解压缩并放入dict中。

    如果您只是为项目中的一个,也许两个视图执行此操作,您会发现它是可管理的,但很快您就会想要使用一个小API,特别是考虑到使用诸如Django REST framework

答案 1 :(得分:0)

在你保存对象的视图中,在保存之后,object.id将包含对象的新id,你可以通过json返回,或者你想要在你的ajax响应中返回,然后是的你会需要将其填入formset行,以便下次提交。

您必须注意的一件事是,django希望所有现有行都位于formset的顶部,而任何新行都位于底部。否则,formset save会抱怨缺少id。因此,如果您在javascript中进行任何类型的排序,那么除非您在formset中对所有字段名称进行相当多的修复,否则您无法做到这一点。 formset代码使用管理表单中的数字来确定要插入哪些行以及要更新哪些行,它不会根据是否存在id来执行此操作。不幸的是...