Voici comment je le fais, en utilisant jQuery :
Mon modèle:
<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>
Dans un fichier 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);
}
Ce qu'il fait:
cloneMoreaccepte selectorcomme premier argument, et typede formset comme 2e argument . Ce qu'il selectorfaut faire, c'est lui transmettre ce qu'il doit reproduire. Dans ce cas, je le passe div.table:lastpour que jQuery recherche la dernière table avec une classe de table. La :lastpartie est importante car le selectorest également utilisé pour déterminer ce que le nouveau formulaire sera inséré après. Il est plus que probable que vous le souhaiteriez à la fin du reste des formulaires. L' typeargument est que nous pouvons mettre à jour le management_formchamp, notamment TOTAL_FORMS, ainsi que les champs de formulaire réels. Si vous avez un jeu de formulaires rempli, par exemple, de Clientmodèles, les champs de gestion auront des ID de id_clients-TOTAL_FORMSet id_clients-INITIAL_FORMS, tandis que les champs de formulaire seront au format id_clients-N-fieldnameavecNétant le numéro de formulaire, en commençant par 0. Donc , avec l' typeargument de la cloneMorefonction ressemble à combien de formes Actuellement , il n'y, et passe par chaque entrée et étiquette à l' intérieur du nouveau formulaire remplaçant tous les noms / ids de quelque chose comme champ id_clients-(N)-nameà id_clients-(N+1)-nameet ainsi de suite. Une fois terminé, il met à jour le TOTAL_FORMSchamp pour refléter le nouveau formulaire et l'ajoute à la fin de l'ensemble.
Cette fonction est particulièrement utile pour moi car la façon dont elle est configurée me permet de l'utiliser dans toute l'application lorsque je veux fournir plus de formulaires dans un jeu de formulaires, et ne me fait pas avoir besoin d'un formulaire "modèle" caché pour dupliquer tant que je lui transmets le nom du jeu de formulaires et le format dans lequel les formulaires sont disposés. J'espère que ça aide.