你会如何在Django中创建一个动态的formset?

问题描述:

这里是我做的方式:你会如何在Django中创建一个动态的formset?

{{ formset.management_form }} 
<table> 
    {% for form in formset.forms %} 
     {{ form }} 
    {% endfor %} 
</table> 
<a href="javascript:void(0)" id="add_form">Add Form</a> 

而这里的JS:

var form_count = {{formset.total_form_count}}; 
$('#add_form').click(function() { 
    form_count++; 
    var form = '{{formset.empty_form|escapejs}}'.replace(/__prefix__/g, form_count); 
    $('#forms').append(form) 
    $('#id_form-TOTAL_FORMS').val(form_count); 
}); 

具体什么困扰我的是,我不得不写escapejs模板标签自己。它只是去除所有换行符,并且转义任何单引号,这样它就不会弄乱我的字符串。但是,在这种情况下,Django制造商究竟希望我们做什么?为什么他们有这个隐藏字段,他们可能刚刚使用了一个像<input name="my_form_field[0]" />这样的数组,然后计算它的长度呢?

+1

但是,你为什么要混合django模板和JavaScript? – Prashanth 2010-03-01 04:38:37

+0

以便我可以处理它。否则,我必须在视图中完全自定义表单处理。 Django似乎鼓励这种方法,那就是*为什么*他们提供了这个'empty_form'和'__prefix__',以便你可以替换它。 – mpen 2010-03-01 06:36:02

+1

我喜欢'.empty_form'的用法 - 很好,很短。谢谢! – 2011-05-24 01:09:26

在Django中有一些地方“为什么”是因为它是如何在Django管理应用程序中实现的,我相信这就是其中之一。因此,答案是他们期望你实现你自己的JavaScript。

查看此SO问题Dynamically adding a form...了解更多javascript的想法。

还有两个可插拔的应用程序可用,django-dynamic-formsetdjango-dinamyc-form,直到现在才查看第一个。

+1

编写我自己的JS并不是一个真正的问题......我只是好奇他们为什么只给我们一半的工具,我们需要......他们说'empty_form'可以是用于这个,但它打印线断行和这样的东西不是很友好的时候尝试填充到JS,除非我误解了一些东西。我认为我更喜欢我的动态formset方法...我怀疑它会减少客户端的压力,并且需要更少的代码:)噢,好吧......我想我只是挑剔,但我仍然真的很不赞同Django的设计决策。 – mpen 2010-03-02 02:39:47

+0

好的,Django恰当的设计决策是保持JS框架中立。管理员是一个contrib应用程序,所以在技术上不是Django核心的一部分,虽然一些功能,如formset(显然)来自于管理员的工作,而我认为管理员是一个很好的应用程序,它可能会受到一定程度的影响从缺乏宏伟的设计。 – 2010-03-02 07:58:26

+3

如果你想用ajax做任何事情或动态添加新对象,Formset是一个巨大的痛苦。 Django尝试设计Web 2.0类型应用程序时,迄今为止最大的问题。出于这个原因,我们在Django投资了6个月后,几乎改用了Java框架,但决定花费太多时间。 – 2011-11-02 06:19:28

这个问题有点旧了,但我花了一段时间才弄清楚了。

我建议将模板中的formset.empty_form呈现为隐藏字段,并在JavaScript中引用此字段。

下面是来自Django管理站点一个复杂的动态表单集例如: (但要注意,它并没有被更新为使用empty_form ....)

[JS] http://code.djangoproject.com/browser/django/trunk/django/contrib/admin/media/js/inlines.js

[HTML模板] http://code.djangoproject.com/browser/django/trunk/django/contrib/admin/templates/admin/edit_inline/tabular.html

+0

我最近(实际上几个小时前)redid这个...它真的讨厌与...一起工作尝试添加和删除窗体,并更新所有分散的ID,并确保至少有一个窗体,并验证他们都正确...与ajax/cascading/contingent选择下拉菜单相结合,它成为一个微型的噩梦。 – mpen 2010-08-11 01:40:19

+0

你有没有从django inlines.js例子中工作?我为我的网站进行了修改(希望在单独的列表中添加按钮)。不是微不足道的(我是js新手,所以需要一段时间),但我想我设法将大部分逻辑包含在一个独立的脚本中。 – bsk 2010-08-11 19:17:01

这是因为formset已创建工作没有JavaScript,只使用通常的HTTP工作流程。

Django是javascript不可知论者。

如果你想添加一些javascript的混合,你可以使用dedicated jquery plugin

+1

希望我能看到演示,但谢谢。 Django的设计目的是在没有JavaScript的情况下工作,是的,但它似乎有一些小的钩子来构建JavaScript ....我只是希望他们更进一步,因为这很痛苦。 – mpen 2012-01-04 22:37:53

+0

@Mark:实际上有一个演示:-)在http://code.google.com/p/django-dynamic-formset/下载该项目,它包含一个django演示。 – 2012-01-05 09:27:41

+0

这不是我演示的意思。我的意思是不必下载它(“现场演示”?)。有数百万个项目和程序在那里......人们喜欢在投入时间和精力,下载和提取内容,和/或安装/编译之前知道他们得到了什么。无论如何,既然你*推荐了它,它不仅仅是我偶然发现的一些随机事物,我会检查出来......(如果它是如此美妙的图书馆,你会期望它会在某个地方使用可以链接到...) – mpen 2012-01-05 16:32:29

在我的情况。我使用了插件django-dynamic-formset(https://code.google.com/p/django-dynamic-formset/wiki/Usage

并修改了选项“added”并且运行良好。

 $('#formset-table tbody tr').formset({ 
      prefix: '{{ formset.prefix }}', 
      formCssClass: '{{ formset.prefix }}-inlineformset', 
      added: function(obj_tr){ 
   var form = $(obj_tr).html().replace(/\-(\w+)\-(\w+)(fix__)\-/g, '-'); 
       $(obj_tr).html(form); 

      }, 

这个正则表达式替换字符串[前缀] - 前缀同行 ' - '

也许不是最好的解决办法,但工作。

当使用formset.empty_form作为字符串时,有一些可能的XSS的情况,将'__prefix__'替换为实际的formset表单索引。我的可插入应用程序将formset.empty_form转换为Knockout.js模板,然后通过自定义Knockout.js绑定进行克隆。此外,Knockout.js会自动重新计算表单字段标识索引,当在添加inlineformsets的整个表单提交之前动态删除新添加的表单集表单表单时。下面是文档:加载与内嵌的JavaScript自定义字段时

https://django-jinja-knockout.readthedocs.org/en/latest/forms.html#dynamically-adding-new-related-formset-forms

Knockout.js还结合防止XSS。