您将如何在 Django 中制作动态表单集?

Posted

技术标签:

【中文标题】您将如何在 Django 中制作动态表单集?【英文标题】:How would you make a dynamic formset in Django? 【发布时间】:2011-01-22 03:52:09 【问题描述】:

这是我的做法:

 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 制造商究竟希望我们做什么呢?为什么他们有这个 TOTAL_FORMS 隐藏字段,而他们本可以使用像 &lt;input name="my_form_field[0]" /&gt; 这样的数组,然后计算它的长度?

【问题讨论】:

但是你为什么要把 django 模板和 javascript 混在一起呢? 我喜欢 .empty_form 的用法 - 又好又短。谢谢! 这个解决方案 IMO 比一般使用的典型克隆方法要好得多。 - 非常适用于具有 javascript 的表单,例如 django-CKeditor - 在没有任何初始表单时也可以工作 - 处理初始数据 有一点,escapejs 是一个内置标签,也许它不是在编写时。同样对于那些不只是想要基本表单的人,您可以执行 formset.empty_form.as_custom|escapejs 其中 as_custom 是一个返回渲染模板的表单函数。 如果此 JS 出现在脚本标记内,您对 escapejs 的描述不会对字符串“”进行属性转义。 __prefix__ 必须替换为 form_count - 1。它从 0 开始,而不是 1。 【参考方案1】:

在 Django 中有几个地方的“原因”是因为它是为 Django 管理应用程序实现的,我相信这是其中之一。因此答案是他们希望您实现自己的 javascript。

查看这个 SO question Dynamically adding a form... 了解更多关于 JavaScript 的想法。

还有两个可插入的应用程序,django-dynamic-formset 和 django-dinamyc-form,直到现在我在查找第一个时才看到它们。

【讨论】:

写我自己的 JS 真的不是问题……我只是好奇他们为什么只给我们需要的工具的一半……他们说empty_form 可以使用为此,它会打印换行符等,在尝试将其填充到 JS 中时使用起来不是很友好,除非我误解了某些东西。我想我更喜欢我的动态表单集方法...我怀疑它给客户端带来的压力更小,并且需要更少的代码:)哦好吧...我想我只是在吹毛求疵,但我仍然非常不同意Django 的设计决策。 好吧,Django 正确的设计决定是保持 JS 框架中立。 admin 是一个 contrib 应用程序,因此从技术上讲不是 Django 核心的一部分,尽管一些功能,例如 formset(显然)来自 admin 的工作,虽然我认为 admin 是一个很好的应用程序,但它可能确实受到了一些影响由于缺乏宏伟的设计。 如果你想用 ajax 做任何事情或动态添加新对象,Formsets 是一个巨大的痛苦。到目前为止,Django 在尝试设计 Web 2.0 类型的应用程序时遇到的最大问题。正是因为这个原因,我们在 Django 上投资了 6 个月后几乎切换到了 Java 框架,但我们认为我们花了太多时间。 你能帮我吗***.com/questions/62285767/…,我尝试了很多但没有得到答案!我非常感谢你【参考方案2】:

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

我建议在您的模板中将 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

【讨论】:

我最近(实际上是几个小时前)重做了这个......使用它真的很讨厌......尝试添加和删除表单,并更新所有分散的 ID,并确保有至少一种形式,并正确验证它们...将其与 ajax/级联/条件选择下拉列表结合起来,它就变成了一场小型噩梦。 您是否使用了 django inlines.js 示例?我为我的网站修改了它(希望在单独的列表中添加按钮)。这不是微不足道的(我是 js 新手,所以花了一段时间),但我想我设法将大部分逻辑包含在一个独立的脚本中。【参考方案3】:

这是因为创建了表单集以无需 javascript,仅使用通常的 HTTP 工作流程。

Django 与 JavaScript 无关。

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

【讨论】:

希望我能看到演示,但谢谢。 Django 被设计为在没有 JavaScript 的情况下工作,是的,但它似乎有一些小钩子可以在其上构建 JavaScript....我只是希望他们能更进一步,因为它很痛苦。 @Mark:实际上有一个演示 :-) 在code.google.com/p/django-dynamic-formset 下载项目,它包含一个 django 演示。 当然,一个人花了很多时间来解决一个复杂的问题,让它开源,创建一个可以在 5 秒内测试和安装的 django 项目,并免费让你的生活变得异常轻松。但我同意,他不够努力,你值得更好,你有权抱怨。 这不是我要说的。你必须从两方面来看它。我相信他做得很好,他通过与世界分享做一件了不起的事情,如果他不想花更多时间来宣传它,那是他的号召,我不会坚持它反对他。我只是说如果没有演示,很多人会忽略它,因为有很多替代品(在这种特定情况下可能没有那么多)有很好的华丽演示 证明它们有效,您可以快速轻松地确定它们是否适合您。 当您尝试评估几十个备选方案时,这不是 5 秒。比较众多程序或软件库是一项巨大的时间投资。您排除它们的速度越快越好(对您而言……也许不是作者)。同样,这并不是说我不欣赏这个人的努力。它很可能正是我想要的。【参考方案4】:

就我而言。我使用了插件 django-dynamic-formset (https://code.google.com/p/django-dynamic-formset/wiki/Usage)

并修改了“添加”选项,效果很好。

        $('#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);

           ,

这个正则表达式替换字符串[prefix]-prefix peer '-'

也许不是最好的解决方案,但有效。

【讨论】:

【参考方案5】:

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

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

在使用内联 Javascript 加载自定义字段时,Knockout.js 绑定还可以防止 XSS。

【讨论】:

以上是关于您将如何在 Django 中制作动态表单集?的主要内容,如果未能解决你的问题,请参考以下文章

Django FormWizard - 如何根据上一步动态创建表单集

如何使用动态过滤器制作 django 查询集?

Django:在表单向导中为步骤动态设置表单集

Django:使用 Jquery 的动态表单集仅保存第一个表单集实例

Django:如何在 ajax 中返回模型表单集并在模板中使用

如何用FastReport制作动态报表