Динамическое добавление формы в набор форм Django с помощью Ajax - PullRequest
251 голосов
/ 02 февраля 2009

Я хочу автоматически добавлять новые формы в набор форм Django с помощью Ajax, чтобы, когда пользователь нажимает кнопку «добавить», он запускал JavaScript, который добавляет новую форму (которая является частью набора форм) на страницу.

Ответы [ 15 ]

209 голосов
/ 21 марта 2009

Вот как я это делаю, используя 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>

В файле 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);
}

Что он делает:

cloneMore принимает selector в качестве первого аргумента, а type набора форм - в качестве второго. То, что selector должен сделать, это передать то, что он должен дублировать. В этом случае я передаю его div.table:last, чтобы jQuery искал последнюю таблицу с классом table. Часть :last важна, потому что selector также используется для определения, какая новая форма будет вставлена ​​после. Скорее всего, вы захотите это в конце остальных форм. Аргумент type таков, что мы можем обновить поле management_form, особенно TOTAL_FORMS, а также фактические поля формы. Если у вас есть форма, полная, скажем, Client моделей, поля управления будут иметь идентификаторы id_clients-TOTAL_FORMS и id_clients-INITIAL_FORMS, тогда как поля формы будут иметь формат id_clients-N-fieldname с формой N номер, начинающийся с 0. Таким образом, с аргументом type функция cloneMore проверяет, сколько форм в настоящее время существует, и проходит через каждый ввод и метку внутри новой формы, заменяя все имена / идентификаторы полей с чем-то вроде id_clients-(N)-name на id_clients-(N+1)-name и скоро. После завершения он обновляет поле TOTAL_FORMS, чтобы отразить новую форму, и добавляет его в конец набора.

Эта функция особенно полезна для меня, потому что способ ее настройки позволяет использовать ее в приложении, когда я хочу предоставить больше форм в наборе форм, и не требует от меня скрытого «шаблона». дублировать форму, пока я передаю ее, имя набора форм и формат, в котором выложены формы. Надеюсь, это поможет.

102 голосов
/ 11 ноября 2011

Упрощенная версия ответа Паоло с использованием 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>
24 голосов
/ 22 марта 2009

Я опубликовал фрагмент из приложения, над которым я работал некоторое время назад. Похож на Paolo, но также позволяет удалять формы.

18 голосов
/ 21 апреля 2009

Предложение Паоло прекрасно работает с одним предупреждением - кнопками браузера назад / вперед.

Динамические элементы, созданные с помощью скрипта Паоло, не будут отображаться, если пользователь возвращается в набор форм с помощью кнопки «назад / вперед». Проблема, которая может быть нарушителем соглашения для некоторых.

Пример:

1) Пользователь добавляет две новые формы в набор форм с помощью кнопки «add-more»

2) Пользователь заполняет формы и отправляет форму

3) Пользователь нажимает кнопку возврата в браузере

4) Formset теперь уменьшен до исходной формы, все динамически добавленные формы отсутствуют

Это вовсе не дефект сценария Паоло; но факт жизни с манипуляциями dom и кешем браузера.

Полагаю, можно сохранить значения формы в сеансе и использовать магию ajax, когда набор форм загружается для повторного создания элементов и перезагрузки значений из сеанса; но в зависимости от того, насколько анальным вы хотите быть с одним и тем же пользователем и несколькими экземплярами формы, это может стать очень сложным.

У кого-нибудь есть хорошее предложение для решения этой проблемы?

Спасибо!

13 голосов
/ 27 ноября 2011

Ознакомьтесь со следующими решениями для динамических форм django:

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

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

Они оба используют jQuery и специфичны для django. Первый выглядит немного более отточенным и предлагает загрузку с отличными демонстрационными версиями.

11 голосов
/ 09 февраля 2009

Имитация и подражание:

  • Создайте набор форм, который соответствует ситуации до , нажав кнопку «Добавить».
  • Загрузите страницу, просмотрите источник и запишите все поля <input>.
  • Измените форму набора в соответствии с ситуацией после нажатием кнопки «добавить» (измените количество дополнительных полей).
  • Загрузите страницу, просмотрите источник и запишите, как изменились поля <input>.
  • Создайте некоторый JavaScript, который соответствующим образом изменяет DOM, чтобы переместить его из состояния до в состояние после .
  • Прикрепите этот JavaScript к кнопке «Добавить».

Хотя я знаю, что наборы форм используют специальные скрытые <input> поля и приблизительно знают, что должен делать скрипт, я не вспоминаю подробности из головы. То, что я описал выше, это то, что я буду делать в вашей ситуации.

4 голосов
/ 04 ноября 2010

Еще одна версия cloneMore, которая позволяет проводить выборочную очистку полей. Используйте его, когда необходимо предотвратить стирание нескольких полей.

$('table tr.add-row a').click(function() {
    toSanitize = new Array('id', 'product', 'price', 'type', 'valid_from', 'valid_until');
    cloneMore('div.formtable table tr.form-row:last', 'form', toSanitize);
});

function cloneMore(selector, type, sanitize) {
    var newElement = $(selector).clone(true);
    var total = $('#id_' + type + '-TOTAL_FORMS').val();
    newElement.find(':input').each(function() {
        var namePure = $(this).attr('name').replace(type + '-' + (total-1) + '-', '');
        var name = $(this).attr('name').replace('-' + (total-1) + '-','-' + total + '-');
        var id = 'id_' + name;
        $(this).attr({'name': name, 'id': id}).removeAttr('checked');

        if ($.inArray(namePure, sanitize) != -1) {
            $(this).val('');
        }

    });
    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);
}
4 голосов
/ 02 февраля 2009

Один из вариантов - создать набор форм с каждой возможной формой, но изначально установить необязательные формы скрытыми, то есть display: none;. Когда необходимо отобразить форму, установите для ее отображения css значение block или любое другое подходящее значение.

Не зная более подробной информации о том, что делает ваш «Аякс», трудно дать более подробный ответ.

2 голосов
/ 25 июля 2011

Я думаю, что это гораздо лучшее решение.

Как бы вы создали динамический набор форм в Django?

Делает ли что-то, клон не делает:

  • Добавить форму, если не существует начальной формы
  • Лучше обрабатывает javascript в форме, например, django-ckeditor
  • Сохранить исходные данные
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...