Spec-Zone.ru › Django 1.8

Наборы форм

class BaseFormSet [source]

Набор форм — это уровень абстракции для работы с несколькими формами на одной странице. Его можно сравнить с таблицей данных. Предположим, у вас есть следующая форма:

>>> 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)

Перебирая formset , формы будут отображаться в порядке их создания. Вы можете изменить этот порядок, предоставив альтернативную реализацию для метода __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 будет влиять на валидацию. См. Валидация количества форм в наборе форм.

Валидация набора форм

Валидация с набором форм почти идентична обычной Form. В наборе форм есть метод 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 — это список, чьи элементы соответствуют формам в наборе форм. Валидация выполняется для каждой из двух форм, и отображается ожидаемое сообщение об ошибке для второго элемента.

BaseFormSet.total_error_count() [source]

Чтобы проверить количество ошибок в наборе форм, мы можем использовать метод 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 }} (заменив имя вашего набора форм соответствующим образом).

total_form_count и initial_form_count

BaseFormSet имеет несколько методов, тесно связанных с ManagementForm, total_form_count и initial_form_count.

total_form_count возвращает общее количество форм в наборе форм. initial_form_count возвращает количество форм в наборе форм, которые были предварительно заполнены, и также используется для определения количества необходимых форм. Вам, вероятно, никогда не придётся переопределять ни один из этих методов, поэтому убедитесь, что вы понимаете, что они делают, прежде чем это делать.

empty_form

BaseFormSet предоставляет дополнительный атрибут empty_form , который возвращает экземпляр формы с префиксом __prefix__ для более удобного использования в динамических формах с JavaScript.

Настройка валидации набора форм

У набора форм есть метод clean , аналогичный методу класса Form. Здесь вы определяете собственную валидацию, работающую на уровне набора форм:

>>> from django.forms import BaseFormSet, 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 вызывается после вызова всех методов Form.clean. Ошибки будут найдены с помощью метода non_form_errors() набора форм.

Валидация количества форм в наборе форм

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

validate_max

Если 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 строго, даже если max_num было превышено, потому что количество начальных данных было избыточным.

Примечание

Независимо от validate_max, если количество форм в наборе данных превышает max_num более чем на 1000, форма не будет валидирована так, как если бы validate_max было установлено, а также будут валидированы только первые 1000 форм, превышающих max_num. Остальные будут полностью усечены. Это для защиты от атак на исчерпание памяти с использованием сгенерированных запросов POST.

validate_min

Если 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.']

Параметры min_num и validate_min были добавлены в formset_factory().

Работа с порядком и удалением форм

В formset_factory() предоставляются два необязательных параметра can_order и can_delete для работы с порядком форм в наборах форм и удалением форм из набора форм.

can_order

BaseFormSet.can_order

По умолчанию: 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'}

can_delete

BaseFormSet.can_delete

По умолчанию: 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()

Если вы хотите сохранить обратную совместимость с Django 1.6 и более ранними версиями, вы можете сделать что-то подобное:

>>> try:
>>>     # For Django 1.7+
>>>     for obj in formset.deleted_objects:
>>>         obj.delete()
>>> except AssertionError:
>>>     # Django 1.6 and earlier already deletes the objects, trying to
>>>     # delete them a second time raises an AssertionError.
>>>     pass

С другой стороны, если вы используете обычный FormSet, вам нужно будет самостоятельно обрабатывать formset.deleted_forms, возможно, в методе save() вашего набора форм, так как нет общепринятого понятия удаления формы.

Добавление дополнительных полей в набор форм

Если вам нужно добавить дополнительные поля в набор форм, это можно легко сделать. Базовый класс набора форм предоставляет метод add_fields. Вы можете просто переопределить этот метод, чтобы добавить свои поля или даже переопределить поля/атрибуты по умолчанию для полей порядка и удаления:

>>> from django.forms import BaseFormSet, 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>

Использование набора форм в представлениях и шаблонах

Использование набора форм внутри представления так же просто, как и использование обычного класса Form. Единственное, о чём вам нужно помнить, это убедиться, что вы используете форму управления внутри шаблона. Давайте рассмотрим пример представления:

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 и can_order

Если вы вручную отрисовываете поля в шаблоне, вы можете отрисовать параметр 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,
    })

Затем вы можете отрисовать наборы форм как обычно. Важно отметить, что вам нужно передать prefix как в случае POST, так и в случае не-POST, чтобы обеспечить правильную отрисовку и обработку.

© Django Software Foundation and individual contributors
Licensed under the BSD License.
https://docs.djangoproject.com/en/1.8/topics/forms/formsets/

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API