Набор форм — это абстрактный слой для работы с множеством форм на одной странице. Его можно сравнить с таблицей данных. Скажем у вас есть следующая форма:
>>> from django import forms
>>> class ArticleForm(forms.Form):
... title = forms.CharField()
... pub_date = forms.DateField()
Вы можете позволить пользователю создавать несколько статей за один раз. Для того, чтобы создать набор форм из ArticleForm вам потребуется:
>>> from django.forms import formset_factory
>>> ArticleFormSet = formset_factory(ArticleForm)
Теперь у вас есть класс набора форм ArticleFormSet. Набор форм предоставляет возможность последовательно проходить по списку форм и отображать их как обычные формы:
>>> formset = ArticleFormSet()
>>> for form in formset:
... print(form.as_table())
<tr><th><label for="id_form-0-title">Title:</label></th><td><input type="text" name="form-0-title" id="id_form-0-title" /></td></tr>
<tr><th><label for="id_form-0-pub_date">Pub date:</label></th><td><input type="text" name="form-0-pub_date" id="id_form-0-pub_date" /></td></tr>
Как вы можете видеть, набор добавляет одну пустую форму к своему выводу. Количество выводимых пустых форм управляется с помощью параметра extra. По умолчанию фабрика formset_factory() добавляет одну пустую форму. Следующий пример отобразит две пустые формы:
>>> ArticleFormSet = formset_factory(ArticleForm, extra=2)
Итерация по набору форм отобразит формы в порядке их определения. Вы можете изменить этот порядок, предоставив собственную версию метода __iter__().
К формами внутри набора можно обращаться по индексу. При определении собственного __iter__, вами потребуется также реализовать __getitem__ для сохранения этой возможности.
Возможность назначения начальных данных является одним из ключевых аспектов удобства использования наборов форм. Как было показано выше, вы можете управлять количеством пустых форм, отображаемых набором. Это означает, что вы указываете набору сколько дополнительных пустых форм следует отобразить вместе с формами, которые заполнены начальными данными. Давайте обратимся к следующему примеру:
>>> import datetime
>>> from django.forms import formset_factory
>>> from myapp.forms import ArticleForm
>>> ArticleFormSet = formset_factory(ArticleForm, extra=2)
>>> formset = ArticleFormSet(initial=[
... {'title': 'Django is now open source',
... 'pub_date': datetime.date.today(),}
... ])
>>> for form in formset:
... print(form.as_table())
<tr><th><label for="id_form-0-title">Title:</label></th><td><input type="text" name="form-0-title" value="Django is now open source" id="id_form-0-title" /></td></tr>
<tr><th><label for="id_form-0-pub_date">Pub date:</label></th><td><input type="text" name="form-0-pub_date" value="2008-05-12" id="id_form-0-pub_date" /></td></tr>
<tr><th><label for="id_form-1-title">Title:</label></th><td><input type="text" name="form-1-title" id="id_form-1-title" /></td></tr>
<tr><th><label for="id_form-1-pub_date">Pub date:</label></th><td><input type="text" name="form-1-pub_date" id="id_form-1-pub_date" /></td></tr>
<tr><th><label for="id_form-2-title">Title:</label></th><td><input type="text" name="form-2-title" id="id_form-2-title" /></td></tr>
<tr><th><label for="id_form-2-pub_date">Pub date:</label></th><td><input type="text" name="form-2-pub_date" id="id_form-2-pub_date" /></td></tr>
Выше показаны три формы. Одна с начальными данными и две пустые. Следует отметить, что в качестве начальных данных мы передали список словарей.
См.также
Параметр max_num фабрики formset_factory() предоставляет вам возможность ограничить максимальное количество пустых форм, отображаемых набором:
>>> from django.forms import formset_factory
>>> from myapp.forms import ArticleForm
>>> ArticleFormSet = formset_factory(ArticleForm, extra=2, max_num=1)
>>> formset = ArticleFormSet()
>>> for form in formset:
... print(form.as_table())
<tr><th><label for="id_form-0-title">Title:</label></th><td><input type="text" name="form-0-title" id="id_form-0-title" /></td></tr>
<tr><th><label for="id_form-0-pub_date">Pub date:</label></th><td><input type="text" name="form-0-pub_date" id="id_form-0-pub_date" /></td></tr>
Если значение параметра max_num больше количества существующих объектов, то к набору будет добавлено до extra пустых форм. Так будет происходить пока не будет достигнуто значение max_num. Например, если extra=2 и max_num=2, а набор форм был создан с одним initial элементом, то в данном наборе форм будет отображена одна переданная форма и одна пустая.
Если количество инициализированных форм превышает max_num, все они будут показаны, не взирая на значение max_num и никаких дополнительных форм показано не будет. Например, при``extra=3`` и max_num=1 и набором форм, проинициализированным двумя формами, именно эти две формы и будут отображены.
Присвоение свойству max_num значения None (по умолчанию) устанавливает достаточное ограничение на количество отображаемых форм (1000). На практике это эквивалентно отсутствию ограничения.
По умолчанию, max_num просто определяет количество форм без валидации. Если передать validate_max=True в formset_factory(), max_num будет учитываться при валидации. Смотрите Проверка количества форм.
Проверка набора форм практически совпадает с аналогичной задачей для обычных форм. Набор форм обладает методом is_valid(), который предоставляет удобный способ выполнить проверку всех форм набора:
>>> from django.forms import formset_factory
>>> from myapp.forms import ArticleForm
>>> ArticleFormSet = formset_factory(ArticleForm)
>>> data = {
... 'form-TOTAL_FORMS': '1',
... 'form-INITIAL_FORMS': '0',
... 'form-MAX_NUM_FORMS': '',
... }
>>> formset = ArticleFormSet(data)
>>> formset.is_valid()
True
Мы не передали в набор форм никаких данных, но он успешно прошёл проверку. Набор обладает достаточной логикой, чтобы игнорировать дополнительные незаполненные формы. Но если мы предоставим неправильную статью:
>>> data = {
... 'form-TOTAL_FORMS': '2',
... 'form-INITIAL_FORMS': '0',
... 'form-MAX_NUM_FORMS': '',
... 'form-0-title': 'Test',
... 'form-0-pub_date': '1904-06-16',
... 'form-1-title': 'Test',
... 'form-1-pub_date': '', # <-- this date is missing but required
... }
>>> formset = ArticleFormSet(data)
>>> formset.is_valid()
False
>>> formset.errors
[{}, {'pub_date': ['This field is required.']}]
Как можно увидеть, formset.errors является списком значений, которые связаны с формами набора. Проверка была выполнена для обеих форм и в результате было отображено сообщение об ошибке во второй форме.
Чтобы определить общее количество ошибок, используйте метод total_error_count:
>>> # Using the previous example
>>> formset.errors
[{}, {'pub_date': ['This field is required.']}]
>>> len(formset.errors)
2
>>> formset.total_error_count()
1
У нас есть возможность проверить изменились ли данные относительно начальных значений (т.е форма была отправлена пустой):
>>> data = {
... 'form-TOTAL_FORMS': '1',
... 'form-INITIAL_FORMS': '0',
... 'form-MAX_NUM_FORMS': '',
... 'form-0-title': '',
... 'form-0-pub_date': '',
... }
>>> formset = ArticleFormSet(data)
>>> formset.has_changed()
False
Вы могли обратить внимание на дополнительные поля (form-TOTAL_FORMS, form-INITIAL_FORMS и form-MAX_NUM_FORMS), которые появлялись при выводе набора форм. Эти данные необходимы для работы формы ManagementForm. Эта форма используется набором для управления своей коллекцией форм. Если эти данные не будут предоставлены набору, то будет вызвано исключение:
>>> data = {
... 'form-0-title': 'Test',
... 'form-0-pub_date': '',
... }
>>> formset = ArticleFormSet(data)
>>> formset.is_valid()
Traceback (most recent call last):
...
django.forms.utils.ValidationError: ['ManagementForm data is missing or has been tampered with']
Она используется для отслеживания количества экземпляров отображаемых форм. Если вы добавляете новую форму с помощью JavaScript, вам следует увеличить счётчики в соответствующих полях этой формы. С другой стороны, если вы позволяете удалять существующие объекты через JavaScript, то вы должны обеспечить правильную маркировку этих объектов с помощью form-#-DELETE в данных POST. Ожидается, что все формы присутствуют в данных POST, даже если они “удалены”.
Доступ к форме управления возможен через атрибут набора форм. При отображении формы в шаблоне, вы можете включать в страницу все управляющие данные с помощью {{ my_formset.management_form }} (подставьте имя своего набора).
Класс BaseFormSet имеет ряд методов, которые предназначены для работы с ManagementForm: total_form_count и initial_form_count.
Метод total_form_count возвращает количество форм в наборе. Метод initial_form_count возвращает количество предварительно заполненных форм в наборе, а также используется для определения количества форм, обязательных для заполнения. Скорее всего у вас никогда не возникнет необходимости переопределения этих методов, просто запомните их назначение.
Класс BaseFormSet имеет атрибут empty_form, который возвращает экземпляр формы с префиксом __prefix__, что может упростить динамическое создание форм с помощью JavaScript.
Набор форм имеет метод clean, аналогичный методу класса Form. Переопределите этот метод для реализации собственных проверок данных на уровне набора форм:
>>> from django.forms import BaseFormSet
>>> from django.forms import formset_factory
>>> from myapp.forms import ArticleForm
>>> class BaseArticleFormSet(BaseFormSet):
... def clean(self):
... """Checks that no two articles have the same title."""
... if any(self.errors):
... # Don't bother validating the formset unless each form is valid on its own
... return
... titles = []
... for form in self.forms:
... title = form.cleaned_data['title']
... if title in titles:
... raise forms.ValidationError("Articles in a set must have distinct titles.")
... titles.append(title)
>>> ArticleFormSet = formset_factory(ArticleForm, formset=BaseArticleFormSet)
>>> data = {
... 'form-TOTAL_FORMS': '2',
... 'form-INITIAL_FORMS': '0',
... 'form-MAX_NUM_FORMS': '',
... 'form-0-title': 'Test',
... 'form-0-pub_date': '1904-06-16',
... 'form-1-title': 'Test',
... 'form-1-pub_date': '1912-06-23',
... }
>>> formset = ArticleFormSet(data)
>>> formset.is_valid()
False
>>> formset.errors
[{}, {}]
>>> formset.non_form_errors()
['Articles in a set must have distinct titles.']
Метод clean набора форм вызывается после вызова аналогичного метода всех форм. Ошибки будут найдены с помощью метода non_form_errors() набора форм.
Django предоставляет несколько способов валидации минимального и максимально количества отправленных форм. Если вам нужна более сложная валидация, используйте собственную валидацию для набора форм.
Если передать validate_max=True в formset_factory(), при валидации будет проверенно, что общее количество форм, без учета помеченных для удаления, не больше чем max_num.
>>> from django.forms import formset_factory
>>> from myapp.forms import ArticleForm
>>> ArticleFormSet = formset_factory(ArticleForm, max_num=1, validate_max=True)
>>> data = {
... 'form-TOTAL_FORMS': '2',
... 'form-INITIAL_FORMS': '0',
... 'form-MIN_NUM_FORMS': '',
... 'form-MAX_NUM_FORMS': '',
... 'form-0-title': 'Test',
... 'form-0-pub_date': '1904-06-16',
... 'form-1-title': 'Test 2',
... 'form-1-pub_date': '1912-06-23',
... }
>>> formset = ArticleFormSet(data)
>>> formset.is_valid()
False
>>> formset.errors
[{}, {}]
>>> formset.non_form_errors()
['Please submit 1 or fewer forms.']
При validate_max=True будет ошибка даже если количество инициализированных форм превышает max_num
Примечание
Независимо от validate_max, если количество форм превышает max_num на более чем 1000, будет ошибка валидация как при включенном validate_max, и только первые 1000 форм после max_num буду провалидированы. Остальные будут проигнорированы. Это сделано для защит от атаки на память(memory exhaustion attack) через модифицированный POST запрос.
Если передать validate_min=True в formset_factory(), при валидации будет проверенно, что общее количество форм, без учета помеченных для удаления, больше или равно min_num.
>>> from django.forms import formset_factory
>>> from myapp.forms import ArticleForm
>>> ArticleFormSet = formset_factory(ArticleForm, min_num=3, validate_min=True)
>>> data = {
... 'form-TOTAL_FORMS': '2',
... 'form-INITIAL_FORMS': '0',
... 'form-MIN_NUM_FORMS': '',
... 'form-MAX_NUM_FORMS': '',
... 'form-0-title': 'Test',
... 'form-0-pub_date': '1904-06-16',
... 'form-1-title': 'Test 2',
... 'form-1-pub_date': '1912-06-23',
... }
>>> formset = ArticleFormSet(data)
>>> formset.is_valid()
False
>>> formset.errors
[{}, {}]
>>> formset.non_form_errors()
['Please submit 3 or more forms.']
formset_factory() принимает два необязательных аргумента: can_order и can_delete, которые добавляют возможность сортировки и удаления форм.
Значение по умолчанию: False
Позволяет создавать наборы форм с возможностью сортировки:
>>> from django.forms import formset_factory
>>> from myapp.forms import ArticleForm
>>> ArticleFormSet = formset_factory(ArticleForm, can_order=True)
>>> formset = ArticleFormSet(initial=[
... {'title': 'Article #1', 'pub_date': datetime.date(2008, 5, 10)},
... {'title': 'Article #2', 'pub_date': datetime.date(2008, 5, 11)},
... ])
>>> for form in formset:
... print(form.as_table())
<tr><th><label for="id_form-0-title">Title:</label></th><td><input type="text" name="form-0-title" value="Article #1" id="id_form-0-title" /></td></tr>
<tr><th><label for="id_form-0-pub_date">Pub date:</label></th><td><input type="text" name="form-0-pub_date" value="2008-05-10" id="id_form-0-pub_date" /></td></tr>
<tr><th><label for="id_form-0-ORDER">Order:</label></th><td><input type="number" name="form-0-ORDER" value="1" id="id_form-0-ORDER" /></td></tr>
<tr><th><label for="id_form-1-title">Title:</label></th><td><input type="text" name="form-1-title" value="Article #2" id="id_form-1-title" /></td></tr>
<tr><th><label for="id_form-1-pub_date">Pub date:</label></th><td><input type="text" name="form-1-pub_date" value="2008-05-11" id="id_form-1-pub_date" /></td></tr>
<tr><th><label for="id_form-1-ORDER">Order:</label></th><td><input type="number" name="form-1-ORDER" value="2" id="id_form-1-ORDER" /></td></tr>
<tr><th><label for="id_form-2-title">Title:</label></th><td><input type="text" name="form-2-title" id="id_form-2-title" /></td></tr>
<tr><th><label for="id_form-2-pub_date">Pub date:</label></th><td><input type="text" name="form-2-pub_date" id="id_form-2-pub_date" /></td></tr>
<tr><th><label for="id_form-2-ORDER">Order:</label></th><td><input type="number" name="form-2-ORDER" id="id_form-2-ORDER" /></td></tr>
Здесь добавляется дополнительное поле к каждой форме. Поле называется ORDER и представлено в виде forms.IntegerField. Для форм, которые были созданы с помощью начальных данных, это поле будет автоматически заполнено их порядковым номером. Давайте рассмотрим, что произойдёт, если пользователь изменит эти значения:
>>> data = {
... 'form-TOTAL_FORMS': '3',
... 'form-INITIAL_FORMS': '2',
... 'form-MAX_NUM_FORMS': '',
... 'form-0-title': 'Article #1',
... 'form-0-pub_date': '2008-05-10',
... 'form-0-ORDER': '2',
... 'form-1-title': 'Article #2',
... 'form-1-pub_date': '2008-05-11',
... 'form-1-ORDER': '1',
... 'form-2-title': 'Article #3',
... 'form-2-pub_date': '2008-05-01',
... 'form-2-ORDER': '0',
... }
>>> formset = ArticleFormSet(data, initial=[
... {'title': 'Article #1', 'pub_date': datetime.date(2008, 5, 10)},
... {'title': 'Article #2', 'pub_date': datetime.date(2008, 5, 11)},
... ])
>>> formset.is_valid()
True
>>> for form in formset.ordered_forms:
... print(form.cleaned_data)
{'pub_date': datetime.date(2008, 5, 1), 'ORDER': 0, 'title': 'Article #3'}
{'pub_date': datetime.date(2008, 5, 11), 'ORDER': 1, 'title': 'Article #2'}
{'pub_date': datetime.date(2008, 5, 10), 'ORDER': 2, 'title': 'Article #1'}
Значение по умолчанию: False
Позволяет создавать наборы форм с возможностью удаления их элементов:
>>> from django.forms import formset_factory
>>> from myapp.forms import ArticleForm
>>> ArticleFormSet = formset_factory(ArticleForm, can_delete=True)
>>> formset = ArticleFormSet(initial=[
... {'title': 'Article #1', 'pub_date': datetime.date(2008, 5, 10)},
... {'title': 'Article #2', 'pub_date': datetime.date(2008, 5, 11)},
... ])
>>> for form in formset:
... print(form.as_table())
<tr><th><label for="id_form-0-title">Title:</label></th><td><input type="text" name="form-0-title" value="Article #1" id="id_form-0-title" /></td></tr>
<tr><th><label for="id_form-0-pub_date">Pub date:</label></th><td><input type="text" name="form-0-pub_date" value="2008-05-10" id="id_form-0-pub_date" /></td></tr>
<tr><th><label for="id_form-0-DELETE">Delete:</label></th><td><input type="checkbox" name="form-0-DELETE" id="id_form-0-DELETE" /></td></tr>
<tr><th><label for="id_form-1-title">Title:</label></th><td><input type="text" name="form-1-title" value="Article #2" id="id_form-1-title" /></td></tr>
<tr><th><label for="id_form-1-pub_date">Pub date:</label></th><td><input type="text" name="form-1-pub_date" value="2008-05-11" id="id_form-1-pub_date" /></td></tr>
<tr><th><label for="id_form-1-DELETE">Delete:</label></th><td><input type="checkbox" name="form-1-DELETE" id="id_form-1-DELETE" /></td></tr>
<tr><th><label for="id_form-2-title">Title:</label></th><td><input type="text" name="form-2-title" id="id_form-2-title" /></td></tr>
<tr><th><label for="id_form-2-pub_date">Pub date:</label></th><td><input type="text" name="form-2-pub_date" id="id_form-2-pub_date" /></td></tr>
<tr><th><label for="id_form-2-DELETE">Delete:</label></th><td><input type="checkbox" name="form-2-DELETE" id="id_form-2-DELETE" /></td></tr>
Подобно can_order, использование этого аргумента добавляет новое поле DELETE в виде forms.BooleanField. При обработке данных набора форм, вы можете получить доступ ко всем помеченным полям через свойство deleted_forms:
>>> data = {
... 'form-TOTAL_FORMS': '3',
... 'form-INITIAL_FORMS': '2',
... 'form-MAX_NUM_FORMS': '',
... 'form-0-title': 'Article #1',
... 'form-0-pub_date': '2008-05-10',
... 'form-0-DELETE': 'on',
... 'form-1-title': 'Article #2',
... 'form-1-pub_date': '2008-05-11',
... 'form-1-DELETE': '',
... 'form-2-title': '',
... 'form-2-pub_date': '',
... 'form-2-DELETE': '',
... }
>>> formset = ArticleFormSet(data, initial=[
... {'title': 'Article #1', 'pub_date': datetime.date(2008, 5, 10)},
... {'title': 'Article #2', 'pub_date': datetime.date(2008, 5, 11)},
... ])
>>> [form.cleaned_data for form in formset.deleted_forms]
[{'DELETE': True, 'pub_date': datetime.date(2008, 5, 10), 'title': 'Article #1'}]
Если вы используете ModelFormSet, объекты удаленных форм будут удалены при выполнении formset.save().
Если выполнить formset.save(commit=False), объекты не будут удалены автоматически. Вам необходимо вызвать delete() для каждого объекта из formset.deleted_objects:
>>> instances = formset.save(commit=False)
>>> for obj in formset.deleted_objects:
... obj.delete()
Если же вы используете просто FormSet, можете делать что хотите с formset.deleted_forms, возможно в переопределенном методе save(). Django просто не знает что должно произойти при удалении таких форм.
При необходимости добавить дополнительные поля к набору форм, следует воспользоваться методом add_fields, который определён в базовом классе набора форм. Вы можете просто переопределить этот метод для того, чтобы добавлять свои собственные поля или даже изменять стандартные поля и/или атрибуты сортировки и удаления полей:
>>> from django.forms import BaseFormSet
>>> from django.forms import formset_factory
>>> from myapp.forms import ArticleForm
>>> class BaseArticleFormSet(BaseFormSet):
... def add_fields(self, form, index):
... super(BaseArticleFormSet, self).add_fields(form, index)
... form.fields["my_field"] = forms.CharField()
>>> ArticleFormSet = formset_factory(ArticleForm, formset=BaseArticleFormSet)
>>> formset = ArticleFormSet()
>>> for form in formset:
... print(form.as_table())
<tr><th><label for="id_form-0-title">Title:</label></th><td><input type="text" name="form-0-title" id="id_form-0-title" /></td></tr>
<tr><th><label for="id_form-0-pub_date">Pub date:</label></th><td><input type="text" name="form-0-pub_date" id="id_form-0-pub_date" /></td></tr>
<tr><th><label for="id_form-0-my_field">My field:</label></th><td><input type="text" name="form-0-my_field" id="id_form-0-my_field" /></td></tr>
Ваша форма может принимать дополнительные параметры, например MyArticleForm. Вы можете передать из при создании набора форм:
>>> from django.forms import BaseFormSet
>>> from django.forms import formset_factory
>>> from myapp.forms import ArticleForm
>>> class MyArticleForm(ArticleForm):
... def __init__(self, *args, **kwargs):
... self.user = kwargs.pop('user')
... super(MyArticleForm, self).__init__(*args, **kwargs)
>>> ArticleFormSet = formset_factory(MyArticleForm)
>>> formset = ArticleFormSet(form_kwargs={'user': request.user})
form_kwargs может зависеть от конкретного экземпляра формы. Набор форм предоставляет метод get_form_kwargs. Этот метод принимает единственный аргумент - норме формы в наборе форм. Номер равен None для empty_form:
>>> from django.forms import BaseFormSet
>>> from django.forms import formset_factory
>>> class BaseArticleFormSet(BaseFormSet):
... def get_form_kwargs(self, index):
... kwargs = super(BaseArticleFormSet, self).get_form_kwargs(index)
... kwargs['custom_kwarg'] = index
... return kwargs
Был добавлен аргумент form_kwargs.
Простота использования наборов форм в представлении аналогична использованию обычной формы. Следует помнить только о том, что необходимо использовать управляемую форму внутри шаблона. Рассмотрим пример представления:
from django.forms import formset_factory
from django.shortcuts import render_to_response
from myapp.forms import ArticleForm
def manage_articles(request):
ArticleFormSet = formset_factory(ArticleForm)
if request.method == 'POST':
formset = ArticleFormSet(request.POST, request.FILES)
if formset.is_valid():
# do something with the formset.cleaned_data
pass
else:
formset = ArticleFormSet()
return render_to_response('manage_articles.html', {'formset': formset})
Шаблон manage_articles.html может выглядеть так:
<form method="post" action="">
{{ formset.management_form }}
<table>
{% for form in formset %}
{{ form }}
{% endfor %}
</table>
</form>
Тем не менее, вышеприведённый код можно сократить и позволить набору самостоятельно обеспечивать вывод управляющей формы:
<form method="post" action="">
<table>
{{ formset }}
</table>
</form>
Пример завершается вызовом метода as_table набора форм.
Если вы вручную создаёте эти поля в шаблоне, то вы можете отобразить параметр can_delete с помощью {{ form.DELETE }}:
<form method="post" action="">
{{ formset.management_form }}
{% for form in formset %}
<ul>
<li>{{ form.title }}</li>
<li>{{ form.pub_date }}</li>
{% if formset.can_delete %}
<li>{{ form.DELETE }}</li>
{% endif %}
</ul>
{% endfor %}
</form>
Аналогично, если набор форм может выполнять сортировку (can_order=True), то соответствующее поле можно вывести с помощью {{ form.ORDER }}.
Можно использовать несколько наборов форм в представлении. Наборы форм очень похожи своим поведением на обычные формы. То есть, можно использовать prefix для их различения при использовании нескольких наборов форм. Давайте рассмотрим пример такой реализации:
from django.forms import formset_factory
from django.shortcuts import render_to_response
from myapp.forms import ArticleForm, BookForm
def manage_articles(request):
ArticleFormSet = formset_factory(ArticleForm)
BookFormSet = formset_factory(BookForm)
if request.method == 'POST':
article_formset = ArticleFormSet(request.POST, request.FILES, prefix='articles')
book_formset = BookFormSet(request.POST, request.FILES, prefix='books')
if article_formset.is_valid() and book_formset.is_valid():
# do something with the cleaned_data on the formsets.
pass
else:
article_formset = ArticleFormSet(prefix='articles')
book_formset = BookFormSet(prefix='books')
return render_to_response('manage_articles.html', {
'article_formset': article_formset,
'book_formset': book_formset,
})
После этого вы можете отображать наборы форм как обычно. Важно помнить, что надо передать префикс набора форм в каждый экземпляр набора, это гарантирует их правильную работу.
Mar 31, 2016