É assim que eu faço, usando o jQuery :
Meu modelo:
<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>
Em um arquivo 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);
}
O que faz:
cloneMore
aceita selector
como o primeiro argumento e o type
formset como o 2º. O que o que selector
deve fazer é passar o que deve duplicar. Nesse caso, eu o passo div.table:last
para que o jQuery procure a última tabela com uma classe de table
. A :last
parte disso é importante porque selector
também é usada para determinar o que o novo formulário será inserido depois. É provável que você queira isso no final dos demais formulários. O type
argumento é para que possamos atualizar o management_form
campo, principalmente TOTAL_FORMS
, bem como os campos reais do formulário. Se você tem um formset cheio de, digamos, Client
modelos, os campos de gestão terá IDs de id_clients-TOTAL_FORMS
e id_clients-INITIAL_FORMS
, enquanto os campos do formulário será em um formato de id_clients-N-fieldname
comN
sendo o número do formulário, começando com 0
. Assim, com o type
argumento cloneMore
de função analisa a forma como muitas formas atualmente existem, e passa por cada entrada e etiqueta dentro da nova forma de substituir todos os nomes de campo / ids de algo como id_clients-(N)-name
a id_clients-(N+1)-name
e assim por diante. Depois de concluído, ele atualiza o TOTAL_FORMS
campo para refletir o novo formulário e o adiciona ao final do conjunto.
Essa função é particularmente útil para mim porque, da maneira como está configurada, permite que eu a use em todo o aplicativo quando quero fornecer mais formulários em um conjunto de formulários e não me faz precisar ter um "modelo" oculto para duplicar contanto que eu o transmita, o nome do conjunto de formulários e o formato em que os formulários são dispostos. Espero que ajude.