Как бы вы создали динамический набор форм в 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 '-'
возможно не лучшее решение, но сработало.