使用Ajax动态地将表单添加到Django formset

Chi*_*Tol 253 django ajax

我想使用Ajax自动将新表单添加到Django表单集中,这样当用户单击"添加"按钮时,它会运行JavaScript,向页面添加一个新表单(它是表单集的一部分).

Pao*_*ino 213

我是这样做的,使用jQuery:

我的模板:

<h3>My Services</h3>
{{ serviceFormset.management_form }}
{% for form in serviceFormset.forms %}
    <div class='table'>
    <table class='no_error'>
        {{ form.as_table }}
    </table>
    </div>
{% endfor %}
<input type="button" value="Add More" id="add_more">
<script>
    $('#add_more').click(function() {
        cloneMore('div.table:last', 'service');
    });
</script>
Run Code Online (Sandbox Code Playgroud)

在javascript文件中:

function cloneMore(selector, type) {
    var newElement = $(selector).clone(true);
    var total = $('#id_' + type + '-TOTAL_FORMS').val();
    newElement.find(':input').each(function() {
        var name = $(this).attr('name').replace('-' + (total-1) + '-','-' + total + '-');
        var id = 'id_' + name;
        $(this).attr({'name': name, 'id': id}).val('').removeAttr('checked');
    });
    newElement.find('label').each(function() {
        var newFor = $(this).attr('for').replace('-' + (total-1) + '-','-' + total + '-');
        $(this).attr('for', newFor);
    });
    total++;
    $('#id_' + type + '-TOTAL_FORMS').val(total);
    $(selector).after(newElement);
}
Run Code Online (Sandbox Code Playgroud)

它能做什么:

cloneMore接受selector作为第一个参数,typeformset作为第二个参数.什么是selector应该做的是把它传递它应该复制.在这种情况下,我传递它,div.table:last以便jQuery查找具有类的最后一个表table.它的:last一部分很重要,因为selector它也用于确定之后插入新表格的内容.很可能你会在其余表格结束时想要它.这个type论点是我们可以更新management_form字段,特别是TOTAL_FORMS实际的表单字段.如果你有一个表单集完整的,也就是说,Client车型,管理领域将有标识id_clients-TOTAL_FORMSid_clients-INITIAL_FORMS,而表单字段将在格式id_clients-N-fieldnameN为发票号,开始0.所以与type参数cloneMore函数着眼于如何多种形式当前有,并通过新的形式,从像更换所有的字段名/ IDS内的每个输入和标签去id_clients-(N)-nameid_clients-(N+1)-name等.完成后,它会更新TOTAL_FORMS字段以反映新表单并将其添加到集合的末尾.

这个函数对我特别有用,因为它的设置方式允许我在整个应用程序中使用它,当我想在formset中提供更多的表单时,并不需要我有一个隐藏的"模板"表单来复制只要我传递formset名称和表单的格式.希望能帮助到你.

  • 我修改了这个以使选择器没有:last并使用了var total = $(selector).length; 得到我的总数,因为刷新页面会删除我的表格集,但保留TOTAL增加导致错误的号码被保存.然后我添加:根据需要最后到选择器.谢谢你. (3认同)
  • 我发现这是使用$(this).attr({'name':name,'id':id}).val('').removeAttr('checked'); 清除输入会使复选框搞乱.设置val('')给复选框一个空值属性.由于复选框不使用value属性,因此无论您点击它多少次都不会更新.但似乎价值优先于复选框的"已检查".这意味着您将始终发布未选中的复选框. (2认同)

Dav*_*ave 108

Paolo使用empty_form模板作为模板的简化版本.

<h3>My Services</h3>
{{ serviceFormset.management_form }}
<div id="form_set">
    {% for form in serviceFormset.forms %}
        <table class='no_error'>
            {{ form.as_table }}
        </table>
    {% endfor %}
</div>
<input type="button" value="Add More" id="add_more">
<div id="empty_form" style="display:none">
    <table class='no_error'>
        {{ serviceFormset.empty_form.as_table }}
    </table>
</div>
<script>
    $('#add_more').click(function() {
        var form_idx = $('#id_form-TOTAL_FORMS').val();
        $('#form_set').append($('#empty_form').html().replace(/__prefix__/g, form_idx));
        $('#id_form-TOTAL_FORMS').val(parseInt(form_idx) + 1);
    });
</script>
Run Code Online (Sandbox Code Playgroud)


elo*_*0ka 25

我已经发布了一段我曾经工作的应用程序的代码片段.与Paolo相似,但也允许您删除表格.


cet*_*eek 18

Paolo的建议很好地解决了一个问题 - 浏览器的后退/前进按钮.

如果用户使用后退/前进按钮返回到formset,则不会呈现使用Paolo脚本创建的动态元素.对某些人来说可能是一个交易破坏者的问题.

例:

1)用户使用"添加更多"按钮向表单集添加两个新表单

2)用户填充表单并提交表单集

3)用户单击浏览器中的后退按钮

4)Formset现在缩减为原始形式,所有动态添加的形式都不存在

这根本不是Paolo脚本的缺陷; 但dom操作和浏览器缓存是生活中的事实.

我想可以在会话中存储表单的值,并且当formset加载以再次创建元素并从会话重新加载值时,可以使用一些ajax魔法; 但取决于你想要关于同一个用户和表单的多个实例的肛门,这可能会变得非常复杂.

任何人都有一个很好的建议处理这个?

谢谢!

  • 如果在成功提交后重定向,则后退按钮不是问题.如果您在下次访问时填写数据库中的表单,则所有表单最初都会显示.如果由于输入无效而导致表单失败,则所有这些表单都应该在重新显示时出现错误.除非我不理解你的陈述......那个帖子提交重定向在一个好的工作应用程序中非常重要,许多程序员根据我在网络上遇到的表现不佳的应用程序的数量而得不到. (2认同)

Kre*_*hek 13

查看动态django表单的以下解决方案:

http://code.google.com/p/django-dynamic-formset/

https://github.com/javisantana/django-dinamyc-form/tree/master/frm

他们都使用jQuery并且是特定于django的.第一个似乎更精致,并提供了一个非常好的演示下载.


aka*_*ola 11

模拟和模仿:

  • 单击"添加"按钮之前创建与该情况对应的表单集.
  • 加载页面,查看源并记下所有<input>字段.
  • 单击"添加"按钮(更改额外字段的数量)后,修改formset以对应于该情况.
  • 加载页面,查看源并记下<input>字段的更改方式.
  • 创建一些JavaScript,以适当的方式修改DOM,将其从before状态移动到after状态.
  • 将JavaScript附加到"添加"按钮.

虽然我知道formsets使用特殊的隐藏<input>字段并且大致知道脚本必须做什么,但我不记得我头脑中的细节.我上面描述的是我在你的情况下会做的.


小智 7

对于正在寻找资源以更好地理解上述解决方案的编码人员:

Django 动态表单集

阅读上面的链接后,Django 文档和以前的解决方案应该更有意义。

Django 表单集文档

作为对我感到困惑的内容的快速总结:管理表格包含其中表格的概述。您必须保持该信息准确,以便 Django 能够识别您添加的表单。(社区,如果我的某些措辞有误,请给我建议。我是 Django 新手。)


e-s*_*tis 6

有一个jquery插件,我使用它与Django 1.3中设置的inline_form,它完美地工作,包括预填充,客户端表单添加,删除和多个inline_formsets.