Как сделать динамический набор форм в 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]" />, а затем подсчитали его длину?

Ответ 1

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

См. этот вопрос SO Динамическое добавление формы... для еще нескольких идей javascript.

Доступны также два подключаемых приложения, django-dynamic-formset и django-dinamyc-form, который я не видел до этого момента, когда смотрел первый.

Ответ 2

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

Я предлагаю визуализировать formet.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

Ответ 3

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

Django является агностиком javascript.

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

Ответ 4

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

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

Ответ 5

Есть некоторые случаи возможного 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#dynamically-adding-new-related-formset-forms

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