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

Вот как я это делаю:

{{ 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 скрытое поле, когда они могли просто использовать массив, как <input name="my_form_field[0]" /> а потом посчитал его длину вместо?

5 ответов

Решение

В Django есть несколько мест, где "причина" в том, что именно так это было реализовано для приложения администратора Django, и я считаю, что это одно из них. Таким образом, ответ - они ожидают, что вы реализуете свой собственный javascript.

Посмотрите этот ТАК вопрос, Динамически добавляя форму... для некоторых других идей JavaScript.

Также доступны два подключаемых приложения: http://code.google.com/p/django-dynamic-formset/ и django-dinamyc-form, которых я не видел до сих пор, когда искал первое.

Этот вопрос немного устарел, но мне понадобилось время, чтобы понять это.

Я предлагаю сделать 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

Это потому, что formset был создан для работы без JavaScript, используя только обычный рабочий процесс HTTP.

Джанго является независимым от JavaScript.

Если вы хотите добавить немного javascript в микс, вы можете использовать специальный плагин jquery.

Есть несколько случаев возможного использования XSS при использовании formset.empty_form как строка, заменяющая '__prefix__' к фактическому индексу формы набора форм. Мое подключаемое приложение конвертирует formset.empty_form в шаблон Knockout.js, который затем клонируется с помощью пользовательских привязок Knockout.js. Кроме того, Knockout.js автоматически пересчитывает индексы идентификатора поля формы, когда вновь добавленная форма набора форм динамически удаляется до того, как была отправлена ​​вся форма с inlineformsets. Вот документация:

https://django-jinja-knockout.readthedocs.org/en/latest/forms.html

Привязка Knockout.js также предотвращает XSS при загрузке пользовательских полей со встроенным Javascript.

В моем случае. я использовал плагин 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);

           },

это регулярное выражение заменяет строку [префикс]-префикс peer '-'

возможно не лучшее решение, но сработало.

Другие вопросы по тегам