Класс BaseFormSet¶
Набор форм – это уровень абстракции для работы с несколькими формами на одной странице. Это может быть лучше по сравнению с сеткой данных. Допустим, у вас есть следующая форма:
1 2 3 4 |
<strong>>>> </strong><strong>from</strong> <strong>django</strong> <strong>import</strong> forms <strong>>>> </strong><strong>class</strong> <strong>ArticleForm</strong>(forms.Form): <strong>... </strong> title = forms.CharField() <strong>... </strong> pub_date = forms.DateField() |
Вы можете разрешить пользователю создавать несколько статей одновременно. Чтобы создать набор форм из ArticleForm, вы должны сделать:
1 2 |
<span class="gp">>>> </span><span class="kn">from</span> <span class="nn">django.forms</span> <span class="k">import</span> <span class="n">formset_factory</span> <span class="gp">>>> </span><span class="n">ArticleFormSet</span> <span class="o">=</span> <span class="n">formset_factory</span><span class="p">(</span><span class="n">ArticleForm</span><span class="p">)</span> |
Теперь вы создали класс formset с именем ArticleFormSet. Создание набора форм дает вам возможность перебирать формы в наборе форм и отображать их так же, как в обычной форме:
1 2 3 4 |
<span class="gp">>>> </span><span class="k">for</span> <span class="n">form</span> <span class="ow">in</span> <span class="n">formset</span><span class="p">:</span> <span class="gp">... </span> <span class="nb">print</span><span class="p">(</span><span class="n">form</span><span class="o">.</span><span class="n">as_table</span><span class="p">())</span> <span class="go"><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></span> <span class="go"><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></span> |
И вы можете увидеть только одну пустую форму. Количество отображаемых пустых форм определяется дополнительным параметром. По умолчанию formset_factory () определяет одну дополнительную форму; В следующем примере будет создан класс formset для отображения двух пустых форм:
1 |
<span class="gp">>>> </span><span class="n">ArticleFormSet</span> <span class="o">=</span> <span class="n">formset_factory</span><span class="p">(</span><span class="n">ArticleForm</span><span class="p">,</span> <span class="n">extra</span><span class="o">=</span><span class="mi">2</span><span class="p">)</span> |
Итерирование по набору форм будет отображать формы в порядке их создания. Вы можете изменить этот порядок, предоставив альтернативную реализацию для метода __iter __ ().
Однако в этом случае, для правильной работы Formsets, если вы переопределите __iter__, вам также потребуется переопределить __getitem__, чтобы иметь корректное поведение.
Использование исходных данных с набором форм
Исходные данные – это то, что определяет основное удобство использования набора форм. Как показано выше, вы можете определить количество дополнительных форм. Это означает, что вы сообщаете набору форм, сколько дополнительных форм нужно показать в дополнение к количеству форм, которые он генерирует из исходных данных. Давайте посмотрим на пример:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
<strong>import</strong> <strong>datetime</strong> <strong>>>> </strong><strong>from</strong> <strong>django.forms</strong> <strong>import</strong> formset_factory <strong>>>> </strong><strong>from</strong> <strong>myapp.forms</strong> <strong>import</strong> ArticleForm <strong>>>> </strong>ArticleFormSet = formset_factory(ArticleForm, extra=2) <strong>>>> </strong>formset = ArticleFormSet(initial=[ <strong>... </strong> {'title': 'Django is now open source', <strong>... </strong> 'pub_date': datetime.date.today(),} <strong>... </strong>]) <strong>>>> </strong><strong>for</strong> form <strong>in</strong> formset: <strong>... </strong> 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> |
В настоящее время есть три формы, показанные выше. Один для исходных данных, которые были переданы и две дополнительные формы. Также обратите внимание, что мы передаем список словарей в качестве исходных данных.
Если вы используете инициал для отображения набора форм, вы должны передать тот же инициал при обработке отправки этого набора, чтобы набор мог определить, какие формы были изменены пользователем. Например, у вас может быть что-то вроде: ArticleFormSet (request.POST, initial = […]).
Ограничение максимального количества форм
Параметр max_num для formset_factory () дает вам возможность ограничить количество форм, которые будет отображать formset.
Если значение max_num больше, чем количество существующих элементов в исходных данных, в набор форм будет добавлено до дополнительных дополнительных пустых форм, если общее число форм не превышает max_num. Например, если extra = 2 и max_num = 2 и набор форм инициализируется одним начальным элементом, будет отображаться форма для исходного элемента и одна пустая форма.
Если количество элементов в исходных данных превышает max_num, все исходные формы данных будут отображаться независимо от значения max_num, и дополнительные формы не будут отображаться. Например, если extra = 3 и max_num = 1 и набор форм инициализируется с двумя исходными элементами, будут отображены две формы с исходными данными.
Значение max_num None (по умолчанию) накладывает верхний предел на количество отображаемых форм (1000). На практике это эквивалентно безграничному.
По умолчанию max_num влияет только на количество отображаемых форм и не влияет на проверку. Если validate_max = True передается в formset_factory (), то max_num повлияет на валидацию.
Проверка набора форм
Проверка с помощью набора форм практически идентична обычной форме. В наборе форм есть метод is_valid, обеспечивающий удобный способ проверки всех форм в наборе форм:
1 2 3 4 5 6 7 8 9 10 |
<span class="gp">>>> </span><span class="kn">from</span> <span class="nn">myapp.forms</span> <span class="k">import</span> <span class="n">ArticleForm</span> <span class="gp">>>> </span><span class="n">ArticleFormSet</span> <span class="o">=</span> <span class="n">formset_factory</span><span class="p">(</span><span class="n">ArticleForm</span><span class="p">)</span> <span class="gp">>>> </span><span class="n">data</span> <span class="o">=</span> <span class="p">{</span> <span class="gp">... </span> <span class="s1">'form-TOTAL_FORMS'</span><span class="p">:</span> <span class="s1">'1'</span><span class="p">,</span> <span class="gp">... </span> <span class="s1">'form-INITIAL_FORMS'</span><span class="p">:</span> <span class="s1">'0'</span><span class="p">,</span> <span class="gp">... </span> <span class="s1">'form-MAX_NUM_FORMS'</span><span class="p">:</span> <span class="s1">''</span><span class="p">,</span> <span class="gp">... </span><span class="p">}</span> <span class="gp">>>> </span><span class="n">formset</span> <span class="o">=</span> <span class="n">ArticleFormSet</span><span class="p">(</span><span class="n">data</span><span class="p">)</span> <span class="gp">>>> </span><span class="n">formset</span><span class="o">.</span><span class="n">is_valid</span><span class="p">()</span> <span class="go">True</span> |
Мы не передали никаких данных в форму, что привело к правильной форме. Набор форм достаточно умен, чтобы игнорировать дополнительные формы, которые не были изменены. Если мы предоставим недействительную статью:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
<span class="gp">>>> </span><span class="n">data</span> <span class="o">=</span> <span class="p">{</span> <span class="gp">... </span> <span class="s1">'form-TOTAL_FORMS'</span><span class="p">:</span> <span class="s1">'2'</span><span class="p">,</span> <span class="gp">... </span> <span class="s1">'form-INITIAL_FORMS'</span><span class="p">:</span> <span class="s1">'0'</span><span class="p">,</span> <span class="gp">... </span> <span class="s1">'form-MAX_NUM_FORMS'</span><span class="p">:</span> <span class="s1">''</span><span class="p">,</span> <span class="gp">... </span> <span class="s1">'form-0-title'</span><span class="p">:</span> <span class="s1">'Test'</span><span class="p">,</span> <span class="gp">... </span> <span class="s1">'form-0-pub_date'</span><span class="p">:</span> <span class="s1">'1904-06-16'</span><span class="p">,</span> <span class="gp">... </span> <span class="s1">'form-1-title'</span><span class="p">:</span> <span class="s1">'Test'</span><span class="p">,</span> <span class="gp">... </span> <span class="s1">'form-1-pub_date'</span><span class="p">:</span> <span class="s1">''</span><span class="p">,</span> <span class="c1"># <-- this date is missing but required</span> <span class="gp">... </span><span class="p">}</span> <span class="gp">>>> </span><span class="n">formset</span> <span class="o">=</span> <span class="n">ArticleFormSet</span><span class="p">(</span><span class="n">data</span><span class="p">)</span> <span class="gp">>>> </span><span class="n">formset</span><span class="o">.</span><span class="n">is_valid</span><span class="p">()</span> <span class="go">False</span> <span class="gp">>>> </span><span class="n">formset</span><span class="o">.</span><span class="n">errors</span> <span class="go">[{}, {'pub_date': ['This field is required.']}]</span> |
Как мы видим, formset.errors – это список, записи которого соответствуют формам в formset. Проверка была выполнена для каждой из двух форм, и ожидаемое сообщение об ошибке появляется для второго элемента.
Как и при использовании обычной формы, каждое поле в формах набора форм может включать атрибуты HTML, такие как maxlength для проверки браузера. Однако поля формы наборов форм не будут содержать обязательный атрибут, так как эта проверка может быть неправильной при добавлении и удалении форм.
BaseFormSet.total_error_count () ¶
Чтобы проверить, сколько ошибок в наборе форм, мы можем использовать метод total_error_count:
1 2 3 4 5 6 |
<span class="gp">>>> </span><span class="n">formset</span><span class="o">.</span><span class="n">errors</span> <span class="go">[{}, {'pub_date': ['This field is required.']}]</span> <span class="gp">>>> </span><span class="nb">len</span><span class="p">(</span><span class="n">formset</span><span class="o">.</span><span class="n">errors</span><span class="p">)</span> <span class="go">2</span> <span class="gp">>>> </span><span class="n">formset</span><span class="o">.</span><span class="n">total_error_count</span><span class="p">()</span> <span class="go">1</span> |
Мы также можем проверить, отличаются ли данные формы от исходных данных (то есть форма была отправлена без каких-либо данных):
1 2 3 4 5 6 7 8 9 |
<span class="gp">... </span> <span class="s1">'form-TOTAL_FORMS'</span><span class="p">:</span> <span class="s1">'1'</span><span class="p">,</span> <span class="gp">... </span> <span class="s1">'form-INITIAL_FORMS'</span><span class="p">:</span> <span class="s1">'0'</span><span class="p">,</span> <span class="gp">... </span> <span class="s1">'form-MAX_NUM_FORMS'</span><span class="p">:</span> <span class="s1">''</span><span class="p">,</span> <span class="gp">... </span> <span class="s1">'form-0-title'</span><span class="p">:</span> <span class="s1">''</span><span class="p">,</span> <span class="gp">... </span> <span class="s1">'form-0-pub_date'</span><span class="p">:</span> <span class="s1">''</span><span class="p">,</span> <span class="gp">... </span><span class="p">}</span> <span class="gp">>>> </span><span class="n">formset</span> <span class="o">=</span> <span class="n">ArticleFormSet</span><span class="p">(</span><span class="n">data</span><span class="p">)</span> <span class="gp">>>> </span><span class="n">formset</span><span class="o">.</span><span class="n">has_changed</span><span class="p">()</span> <span class="go">False</span> |
Понимание ManagementForm
Возможно, вы заметили дополнительные данные (form-TOTAL_FORMS, form-INITIAL_FORMS и form-MAX_NUM_FORMS), которые были необходимы в данных набора форм выше. Эти данные необходимы для ManagementForm. Эта форма используется набором форм для управления коллекцией форм, содержащихся в наборе форм. Если вы не предоставите эти данные управления, возникнет исключение:
1 |
<span class="gr">django.forms.utils.ValidationError</span>: <span class="n">['ManagementForm data is missing or has been tampered with']</span> |
Он используется для отслеживания количества отображаемых экземпляров форм. Если вы добавляете новые формы с помощью JavaScript, вам также следует увеличить количество полей в этой форме. С другой стороны, если вы используете JavaScript, чтобы разрешить удаление существующих объектов, то вам нужно убедиться, что удаляемые объекты правильно помечены для удаления, включив форму – # – 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.
Проверка пользовательского набора форм¶
Formset имеет метод clean, похожий на метод класса Form. Здесь вы определяете свою собственную проверку, которая работает на уровне набора форм:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
<strong>>>> </strong><strong>from</strong> <strong>django.forms</strong> <strong>import</strong> BaseFormSet <strong>>>> </strong><strong>from</strong> <strong>django.forms</strong> <strong>import</strong> formset_factory <strong>>>> </strong><strong>from</strong> <strong>myapp.forms</strong> <strong>import</strong> ArticleForm <strong>>>> </strong><strong>class</strong> <strong>BaseArticleFormSet</strong>(BaseFormSet): <strong>... </strong> <strong>def</strong> clean(self): <strong>... </strong> <em>"""Checks that no two articles have the same title."""</em> <strong>... </strong> <strong>if</strong> any(self.errors): <strong>... </strong> <em># Don't bother validating the formset unless each form is valid on its own</em> <strong>... </strong> <strong>return</strong> <strong>... </strong> titles = [] <strong>... </strong> <strong>for</strong> form <strong>in</strong> self.forms: <strong>... </strong> <strong>if</strong> self.can_delete <strong>and</strong> self._should_delete_form(form): <strong>... </strong> <strong>continue</strong> <strong>... </strong> title = form.cleaned_data.get('title') <strong>... </strong> <strong>if</strong> title <strong>in</strong> titles: <strong>... </strong> <strong>raise</strong> forms.ValidationError("Articles in a set must have distinct titles.") <strong>... </strong> titles.append(title) <strong>>>> </strong>ArticleFormSet = formset_factory(ArticleForm, formset=BaseArticleFormSet) <strong>>>> </strong>data = { <strong>... </strong> 'form-TOTAL_FORMS': '2', <strong>... </strong> 'form-INITIAL_FORMS': '0', <strong>... </strong> 'form-MAX_NUM_FORMS': '', <strong>... </strong> 'form-0-title': 'Test', <strong>... </strong> 'form-0-pub_date': '1904-06-16', <strong>... </strong> 'form-1-title': 'Test', <strong>... </strong> 'form-1-pub_date': '1912-06-23', <strong>... </strong>} <strong>>>> </strong>formset = ArticleFormSet(data) <strong>>>> </strong>formset.is_valid() False <strong>>>> </strong>formset.errors [{}, {}] <strong>>>> </strong>formset.non_form_errors() ['Articles in a set must have distinct titles.'] |
Метод clean для formset вызывается после того, как были вызваны все методы Form.clean. Ошибки будут доступны с помощью метода non_form_errors () в наборе форм.
Проверка количества форм в наборе форм
Django предоставляет несколько способов проверки минимального или максимального количества отправленных форм. Приложения, которые нуждаются в более настраиваемой проверке количества форм, должны использовать пользовательскую проверку набора форм.
validate_max¶
Если validate_max = True передается в formset_factory (), проверка также проверит, что число форм в наборе данных, за исключением тех, которые помечены для удаления, меньше или равно max_num.
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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
<span class="gp">>>> </span><span class="kn">from</span> <span class="nn">myapp.forms</span> <span class="k">import</span> <span class="n">ArticleForm</span> <span class="gp">>>> </span><span class="n">ArticleFormSet</span> <span class="o">=</span> <span class="n">formset_factory</span><span class="p">(</span><span class="n">ArticleForm</span><span class="p">,</span> <span class="n">min_num</span><span class="o">=</span><span class="mi">3</span><span class="p">,</span> <span class="n">validate_min</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span> <span class="gp">>>> </span><span class="n">data</span> <span class="o">=</span> <span class="p">{</span> <span class="gp">... </span> <span class="s1">'form-TOTAL_FORMS'</span><span class="p">:</span> <span class="s1">'2'</span><span class="p">,</span> <span class="gp">... </span> <span class="s1">'form-INITIAL_FORMS'</span><span class="p">:</span> <span class="s1">'0'</span><span class="p">,</span> <span class="gp">... </span> <span class="s1">'form-MIN_NUM_FORMS'</span><span class="p">:</span> <span class="s1">''</span><span class="p">,</span> <span class="gp">... </span> <span class="s1">'form-MAX_NUM_FORMS'</span><span class="p">:</span> <span class="s1">''</span><span class="p">,</span> <span class="gp">... </span> <span class="s1">'form-0-title'</span><span class="p">:</span> <span class="s1">'Test'</span><span class="p">,</span> <span class="gp">... </span> <span class="s1">'form-0-pub_date'</span><span class="p">:</span> <span class="s1">'1904-06-16'</span><span class="p">,</span> <span class="gp">... </span> <span class="s1">'form-1-title'</span><span class="p">:</span> <span class="s1">'Test 2'</span><span class="p">,</span> <span class="gp">... </span> <span class="s1">'form-1-pub_date'</span><span class="p">:</span> <span class="s1">'1912-06-23'</span><span class="p">,</span> <span class="gp">... </span><span class="p">}</span> <span class="gp">>>> </span><span class="n">formset</span> <span class="o">=</span> <span class="n">ArticleFormSet</span><span class="p">(</span><span class="n">data</span><span class="p">)</span> <span class="gp">>>> </span><span class="n">formset</span><span class="o">.</span><span class="n">is_valid</span><span class="p">()</span> <span class="go">False</span> <span class="gp">>>> </span><span class="n">formset</span><span class="o">.</span><span class="n">errors</span> <span class="go">[{}, {}]</span> <span class="gp">>>> </span><span class="n">formset</span><span class="o">.</span><span class="n">non_form_errors</span><span class="p">()</span> <span class="go">['Please submit 3 or more forms.']</span> |
Работа с порядком и удалением форм
Formset_factory () предоставляет два необязательных параметра can_order и can_delete, которые помогают упорядочивать формы в наборах форм и удалять формы из набора форм.
can_order¶
BaseFormSet.can_order¶
По умолчанию: False
Позволяет создать форму с возможностью указание порядка:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
<span class="gp">>>> </span><span class="kn">from</span> <span class="nn">django.forms</span> <span class="k">import</span> <span class="n">formset_factory</span> <span class="gp">>>> </span><span class="kn">from</span> <span class="nn">myapp.forms</span> <span class="k">import</span> <span class="n">ArticleForm</span> <span class="gp">>>> </span><span class="n">ArticleFormSet</span> <span class="o">=</span> <span class="n">formset_factory</span><span class="p">(</span><span class="n">ArticleForm</span><span class="p">,</span> <span class="n">can_order</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span> <span class="gp">>>> </span><span class="n">formset</span> <span class="o">=</span> <span class="n">ArticleFormSet</span><span class="p">(</span><span class="n">initial</span><span class="o">=</span><span class="p">[</span> <span class="gp">... </span> <span class="p">{</span><span class="s1">'title'</span><span class="p">:</span> <span class="s1">'Article #1'</span><span class="p">,</span> <span class="s1">'pub_date'</span><span class="p">:</span> <span class="n">datetime</span><span class="o">.</span><span class="n">date</span><span class="p">(</span><span class="mi">2008</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="mi">10</span><span class="p">)},</span> <span class="gp">... </span> <span class="p">{</span><span class="s1">'title'</span><span class="p">:</span> <span class="s1">'Article #2'</span><span class="p">,</span> <span class="s1">'pub_date'</span><span class="p">:</span> <span class="n">datetime</span><span class="o">.</span><span class="n">date</span><span class="p">(</span><span class="mi">2008</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="mi">11</span><span class="p">)},</span> <span class="gp">... </span><span class="p">])</span> <span class="gp">>>> </span><span class="k">for</span> <span class="n">form</span> <span class="ow">in</span> <span class="n">formset</span><span class="p">:</span> <span class="gp">... </span> <span class="nb">print</span><span class="p">(</span><span class="n">form</span><span class="o">.</span><span class="n">as_table</span><span class="p">())</span> <span class="go"><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></span> <span class="go"><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></span> <span class="go"><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></span> <span class="go"><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></span> <span class="go"><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></span> <span class="go"><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></span> <span class="go"><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></span> <span class="go"><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></span> <span class="go"><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></span> |
Это добавляет дополнительное поле к каждой форме. Это новое поле называется ORDER и представляет собой forms.IntegerField. Для форм из исходных данных им автоматически присваивается числовое значение. Давайте посмотрим, что произойдет, когда пользователь изменит эти значения:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
<span class="gp">>>> </span><span class="n">data</span> <span class="o">=</span> <span class="p">{</span> <span class="gp">... </span> <span class="s1">'form-TOTAL_FORMS'</span><span class="p">:</span> <span class="s1">'3'</span><span class="p">,</span> <span class="gp">... </span> <span class="s1">'form-INITIAL_FORMS'</span><span class="p">:</span> <span class="s1">'2'</span><span class="p">,</span> <span class="gp">... </span> <span class="s1">'form-MAX_NUM_FORMS'</span><span class="p">:</span> <span class="s1">''</span><span class="p">,</span> <span class="gp">... </span> <span class="s1">'form-0-title'</span><span class="p">:</span> <span class="s1">'Article #1'</span><span class="p">,</span> <span class="gp">... </span> <span class="s1">'form-0-pub_date'</span><span class="p">:</span> <span class="s1">'2008-05-10'</span><span class="p">,</span> <span class="gp">... </span> <span class="s1">'form-0-ORDER'</span><span class="p">:</span> <span class="s1">'2'</span><span class="p">,</span> <span class="gp">... </span> <span class="s1">'form-1-title'</span><span class="p">:</span> <span class="s1">'Article #2'</span><span class="p">,</span> <span class="gp">... </span> <span class="s1">'form-1-pub_date'</span><span class="p">:</span> <span class="s1">'2008-05-11'</span><span class="p">,</span> <span class="gp">... </span> <span class="s1">'form-1-ORDER'</span><span class="p">:</span> <span class="s1">'1'</span><span class="p">,</span> <span class="gp">... </span> <span class="s1">'form-2-title'</span><span class="p">:</span> <span class="s1">'Article #3'</span><span class="p">,</span> <span class="gp">... </span> <span class="s1">'form-2-pub_date'</span><span class="p">:</span> <span class="s1">'2008-05-01'</span><span class="p">,</span> <span class="gp">... </span> <span class="s1">'form-2-ORDER'</span><span class="p">:</span> <span class="s1">'0'</span><span class="p">,</span> <span class="gp">... </span><span class="p">}</span> <span class="gp">>>> </span><span class="n">formset</span> <span class="o">=</span> <span class="n">ArticleFormSet</span><span class="p">(</span><span class="n">data</span><span class="p">,</span> <span class="n">initial</span><span class="o">=</span><span class="p">[</span> <span class="gp">... </span> <span class="p">{</span><span class="s1">'title'</span><span class="p">:</span> <span class="s1">'Article #1'</span><span class="p">,</span> <span class="s1">'pub_date'</span><span class="p">:</span> <span class="n">datetime</span><span class="o">.</span><span class="n">date</span><span class="p">(</span><span class="mi">2008</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="mi">10</span><span class="p">)},</span> <span class="gp">... </span> <span class="p">{</span><span class="s1">'title'</span><span class="p">:</span> <span class="s1">'Article #2'</span><span class="p">,</span> <span class="s1">'pub_date'</span><span class="p">:</span> <span class="n">datetime</span><span class="o">.</span><span class="n">date</span><span class="p">(</span><span class="mi">2008</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="mi">11</span><span class="p">)},</span> <span class="gp">... </span><span class="p">])</span> <span class="gp">>>> </span><span class="n">formset</span><span class="o">.</span><span class="n">is_valid</span><span class="p">()</span> <span class="go">True</span> <span class="gp">>>> </span><span class="k">for</span> <span class="n">form</span> <span class="ow">in</span> <span class="n">formset</span><span class="o">.</span><span class="n">ordered_forms</span><span class="p">:</span> <span class="gp">... </span> <span class="nb">print</span><span class="p">(</span><span class="n">form</span><span class="o">.</span><span class="n">cleaned_data</span><span class="p">)</span> <span class="go">{'pub_date': datetime.date(2008, 5, 1), 'ORDER': 0, 'title': 'Article #3'}</span> <span class="go">{'pub_date': datetime.date(2008, 5, 11), 'ORDER': 1, 'title': 'Article #2'}</span> <span class="go">{'pub_date': datetime.date(2008, 5, 10), 'ORDER': 2, 'title': 'Article #1'}</span> |
BaseFormSet также предоставляет атрибут ordering_widget и метод get_ordering_widget (), которые управляют виджетом, используемым с can_order.
BaseFormSet.ordering_widget¶
По умолчанию: NumberInput
Установите ordering_widget, чтобы указать класс виджета, который будет использоваться с can_order:
1 2 3 4 5 |
<span class="gp">>>> </span><span class="kn">from</span> <span class="nn">myapp.forms</span> <span class="k">import</span> <span class="n">ArticleForm</span> <span class="gp">>>> </span><span class="k">class</span> <span class="nc">BaseArticleFormSet</span><span class="p">(</span><span class="n">BaseFormSet</span><span class="p">):</span> <span class="gp">... </span> <span class="n">ordering_widget</span> <span class="o">=</span> <span class="n">HiddenInput</span> <span class="gp">>>> </span><span class="n">ArticleFormSet</span> <span class="o">=</span> <span class="n">formset_factory</span><span class="p">(</span><span class="n">ArticleForm</span><span class="p">,</span> <span class="n">formset</span><span class="o">=</span><span class="n">BaseArticleFormSet</span><span class="p">,</span> <span class="n">can_order</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span> |
get_ordering_widget¶
BaseFormSet.get_ordering_widget () ¶
Переопределите get_ordering_widget (), если вам нужно предоставить экземпляр виджета для использования с can_order:
1 2 3 4 5 6 7 |
<strong>>>> </strong><strong>from</strong> <strong>django.forms</strong> <strong>import</strong> BaseFormSet, formset_factory <strong>>>> </strong><strong>from</strong> <strong>myapp.forms</strong> <strong>import</strong> ArticleForm <strong>>>> </strong><strong>class</strong> <strong>BaseArticleFormSet</strong>(BaseFormSet): <strong>... </strong> <strong>def</strong> get_ordering_widget(self): <strong>... </strong> <strong>return</strong> HiddenInput(attrs={'class': 'ordering'}) <strong>>>> </strong>ArticleFormSet = formset_factory(ArticleForm, formset=BaseArticleFormSet, can_order=<strong>True</strong>) |
can_delete¶
BaseFormSet.can_delete¶
По умолчанию: False
Позволяет создать набор форм с возможностью выбора форм для удаления:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
<strong>>>> </strong><strong>from</strong> <strong>django.forms</strong> <strong>import</strong> formset_factory <strong>>>> </strong><strong>from</strong> <strong>myapp.forms</strong> <strong>import</strong> ArticleForm <strong>>>> </strong>ArticleFormSet = formset_factory(ArticleForm, can_delete=<strong>True</strong>) <strong>>>> </strong>formset = ArticleFormSet(initial=[ <strong>... </strong> {'title': 'Article #1', 'pub_date': datetime.date(2008, 5, 10)}, <strong>... </strong> {'title': 'Article #2', 'pub_date': datetime.date(2008, 5, 11)}, <strong>... </strong>]) <strong>>>> </strong><strong>for</strong> form <strong>in</strong> formset: <strong>... </strong> 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. Когда данные проходят через пометку любого из полей удаления, вы можете получить к ним доступ с помощью delete_forms:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
<strong>>>> </strong>data = { <strong>... </strong> 'form-TOTAL_FORMS': '3', <strong>... </strong> 'form-INITIAL_FORMS': '2', <strong>... </strong> 'form-MAX_NUM_FORMS': '', <strong>... </strong> 'form-0-title': 'Article #1', <strong>... </strong> 'form-0-pub_date': '2008-05-10', <strong>... </strong> 'form-0-DELETE': 'on', <strong>... </strong> 'form-1-title': 'Article #2', <strong>... </strong> 'form-1-pub_date': '2008-05-11', <strong>... </strong> 'form-1-DELETE': '', <strong>... </strong> 'form-2-title': '', <strong>... </strong> 'form-2-pub_date': '', <strong>... </strong> 'form-2-DELETE': '', <strong>... </strong>} <strong>>>> </strong>formset = ArticleFormSet(data, initial=[ <strong>... </strong> {'title': 'Article #1', 'pub_date': datetime.date(2008, 5, 10)}, <strong>... </strong> {'title': 'Article #2', 'pub_date': datetime.date(2008, 5, 11)}, <strong>... </strong>]) <strong>>>> </strong>[form.cleaned_data <strong>for</strong> form <strong>in</strong> 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, чтобы фактически удалить их:
1 2 3 |
<strong>>>> </strong>instances = formset.save(commit=<strong>False</strong>) <strong>>>> </strong><strong>for</strong> obj <strong>in</strong> formset.deleted_objects: <strong>... </strong> obj.delete() |
С другой стороны, если вы используете простой FormSet, вы должны обработать formset.deleted_forms, возможно, в методе save () вашего formset, так как нет общего понятия о том, что означает удаление формы.
Добавление дополнительных полей в набор форм
Если вам нужно добавить дополнительные поля в форму, это может быть легко выполнено. Базовый класс formset предоставляет метод add_fields. Вы можете переопределить этот метод, чтобы добавить свои собственные поля или даже переопределить поля / атрибуты по умолчанию для полей порядка и удаления:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
<strong>>>> </strong><strong>from</strong> <strong>django.forms</strong> <strong>import</strong> BaseFormSet <strong>>>> </strong><strong>from</strong> <strong>django.forms</strong> <strong>import</strong> formset_factory <strong>>>> </strong><strong>from</strong> <strong>myapp.forms</strong> <strong>import</strong> ArticleForm <strong>>>> </strong><strong>class</strong> <strong>BaseArticleFormSet</strong>(BaseFormSet): <strong>... </strong> <strong>def</strong> add_fields(self, form, index): <strong>... </strong> super().add_fields(form, index) <strong>... </strong> form.fields["my_field"] = forms.CharField() <strong>>>> </strong>ArticleFormSet = formset_factory(ArticleForm, formset=BaseArticleFormSet) <strong>>>> </strong>formset = ArticleFormSet() <strong>>>> </strong><strong>for</strong> form <strong>in</strong> formset: <strong>... </strong> 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> |
Передача пользовательских параметров в формы formset
Иногда ваш класс формы принимает пользовательские параметры, такие как MyArticleForm. Вы можете передать этот параметр при создании экземпляра formset:
1 2 3 4 5 6 7 8 9 10 11 |
<strong>>>> </strong><strong>from</strong> <strong>django.forms</strong> <strong>import</strong> BaseFormSet <strong>>>> </strong><strong>from</strong> <strong>django.forms</strong> <strong>import</strong> formset_factory <strong>>>> </strong><strong>from</strong> <strong>myapp.forms</strong> <strong>import</strong> ArticleForm <strong>>>> </strong><strong>class</strong> <strong>MyArticleForm</strong>(ArticleForm): <strong>... </strong> <strong>def</strong> __init__(self, *args, user, **kwargs): <strong>... </strong> self.user = user <strong>... </strong> super().__init__(*args, **kwargs) <strong>>>> </strong>ArticleFormSet = formset_factory(MyArticleForm) <strong>>>> </strong>formset = ArticleFormSet(form_kwargs={'user': request.user}) |
Form_kwargs также может зависеть от конкретного экземпляра формы. Базовый класс formset предоставляет метод get_form_kwargs. Метод принимает один аргумент – индекс формы в наборе форм. Индекс None для empty_form:
1 2 3 4 5 6 7 8 |
<strong>>>> </strong><strong>from</strong> <strong>django.forms</strong> <strong>import</strong> BaseFormSet <strong>>>> </strong><strong>from</strong> <strong>django.forms</strong> <strong>import</strong> formset_factory <strong>>>> </strong><strong>class</strong> <strong>BaseArticleFormSet</strong>(BaseFormSet): <strong>... </strong> <strong>def</strong> get_form_kwargs(self, index): <strong>... </strong> kwargs = super().get_form_kwargs(index) <strong>... </strong> kwargs['custom_kwarg'] = index <strong>... </strong> <strong>return</strong> kwargs |
Настройка префикса formset
В отображаемом HTML формы набора включают префикс для имени каждого поля. По умолчанию префикс «form», но его можно настроить с помощью аргумента префикса formset.
Например, в случае по умолчанию вы можете увидеть:
1 2 |
<<strong>label</strong> for="id_form-0-title">Title:</<strong>label</strong>> <<strong>input</strong> type="text" name="form-0-title" id="id_form-0-title"> |
Но с ArticleFormset (prefix = ‘article’) это становится:
1 2 |
<<strong>label</strong> for="id_article-0-title">Title:</<strong>label</strong>> <<strong>input</strong> type="text" name="article-0-title" id="id_article-0-title"> |
Это полезно, если вы хотите использовать более одного набора форм в представлении.
Использование formset в представлениях и шаблонах
Использование набора форм внутри представления мало чем отличается от использования обычного класса Form. Единственное, о чем вы хотите знать, – это обязательно использовать форму управления внутри шаблона. Смотрите пример:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
<span class="kn">from</span> <span class="nn">django.forms</span> <span class="k">import</span> <span class="n">formset_factory</span> <span class="kn">from</span> <span class="nn">django.shortcuts</span> <span class="k">import</span> <span class="n">render</span> <span class="kn">from</span> <span class="nn">myapp.forms</span> <span class="k">import</span> <span class="n">ArticleForm</span> <span class="k">def</span> <span class="nf">manage_articles</span><span class="p">(</span><span class="n">request</span><span class="p">):</span> <span class="n">ArticleFormSet</span> <span class="o">=</span> <span class="n">formset_factory</span><span class="p">(</span><span class="n">ArticleForm</span><span class="p">)</span> <span class="k">if</span> <span class="n">request</span><span class="o">.</span><span class="n">method</span> <span class="o">==</span> <span class="s1">'POST'</span><span class="p">:</span> <span class="n">formset</span> <span class="o">=</span> <span class="n">ArticleFormSet</span><span class="p">(</span><span class="n">request</span><span class="o">.</span><span class="n">POST</span><span class="p">,</span> <span class="n">request</span><span class="o">.</span><span class="n">FILES</span><span class="p">)</span> <span class="k">if</span> <span class="n">formset</span><span class="o">.</span><span class="n">is_valid</span><span class="p">():</span> <span class="c1"># do something with the formset.cleaned_data</span> <span class="k">pass</span> <span class="k">else</span><span class="p">:</span> <span class="n">formset</span> <span class="o">=</span> <span class="n">ArticleFormSet</span><span class="p">()</span> <span class="k">return</span> <span class="n">render</span><span class="p">(</span><span class="n">request</span><span class="p">,</span> <span class="s1">'manage_articles.html'</span><span class="p">,</span> <span class="p">{</span><span class="s1">'formset'</span><span class="p">:</span> <span class="n">formset</span><span class="p">})</span> |
Тогда шаблон будет иметь вид:
1 2 3 4 5 6 7 8 |
<span class="p"><</span><span class="nt">form</span> <span class="na">method</span><span class="o">=</span><span class="s">"post"</span><span class="p">></span> <span class="cp">{{</span> <span class="nv">formset.management_form</span> <span class="cp">}}</span> <span class="p"><</span><span class="nt">table</span><span class="p">></span> <span class="cp">{%</span> <span class="k">for</span> <span class="nv">form</span> <span class="k">in</span> <span class="nv">formset</span> <span class="cp">%}</span> <span class="cp">{{</span> <span class="nv">form</span> <span class="cp">}}</span> <span class="cp">{%</span> <span class="k">endfor</span> <span class="cp">%}</span> <span class="p"></</span><span class="nt">table</span><span class="p">></span> <span class="p"></</span><span class="nt">form</span><span class="p">></span> |
Однако есть небольшое сокращение для вышеупомянутого, позволяя самому formset иметь дело с формой управления:
1 2 3 4 |
<span class="p"><</span><span class="nt">table</span><span class="p">></span> <span class="cp">{{</span> <span class="nv">formset</span> <span class="cp">}}</span> <span class="p"></</span><span class="nt">table</span><span class="p">></span> <span class="p"></</span><span class="nt">form</span><span class="p">></span> |
Выше описывается вызов метода as_table в классе formset.
Отрисованные вручную can_delete и can_order
Если вы вручную отображаете поля в шаблоне, вы можете отобразить параметр can_delete с помощью {{form.DELETE}}:
1 2 3 4 5 6 7 8 9 10 11 12 |
<span class="p"><</span><span class="nt">form</span> <span class="na">method</span><span class="o">=</span><span class="s">"post"</span><span class="p">></span> <span class="cp">{{</span> <span class="nv">formset.management_form</span> <span class="cp">}}</span> <span class="cp">{%</span> <span class="k">for</span> <span class="nv">form</span> <span class="k">in</span> <span class="nv">formset</span> <span class="cp">%}</span> <span class="p"><</span><span class="nt">ul</span><span class="p">></span> <span class="p"><</span><span class="nt">li</span><span class="p">></span><span class="cp">{{</span> <span class="nv">form.title</span> <span class="cp">}}</span><span class="p"></</span><span class="nt">li</span><span class="p">></span> <span class="p"><</span><span class="nt">li</span><span class="p">></span><span class="cp">{{</span> <span class="nv">form.pub_date</span> <span class="cp">}}</span><span class="p"></</span><span class="nt">li</span><span class="p">></span> <span class="cp">{%</span> <span class="k">if</span> <span class="nv">formset.can_delete</span> <span class="cp">%}</span> <span class="p"><</span><span class="nt">li</span><span class="p">></span><span class="cp">{{</span> <span class="nv">form.DELETE</span> <span class="cp">}}</span><span class="p"></</span><span class="nt">li</span><span class="p">></span> <span class="cp">{%</span> <span class="k">endif</span> <span class="cp">%}</span> <span class="p"></</span><span class="nt">ul</span><span class="p">></span> <span class="cp">{%</span> <span class="k">endfor</span> <span class="cp">%}</span> <span class="p"></</span><span class="nt">form</span><span class="p">></span> |
Аналогично, если у formset есть возможность упорядочить (can_order = True), его можно отобразить с помощью {{form.ORDER}}.
Использование более одного набора форм в представлении
Вы можете использовать более одного набора форм в представлении, если хотите. Formsets заимствуют большую часть своего поведения из форм. При этом вы можете использовать префикс для префикса имен полей формы набора с заданным значением, чтобы разрешить отправку более одного набора форм в представление без конфликта имен. Давайте посмотрим, как это можно сделать:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
<span class="kn">from</span> <span class="nn">django.forms</span> <span class="k">import</span> <span class="n">formset_factory</span> <span class="kn">from</span> <span class="nn">django.shortcuts</span> <span class="k">import</span> <span class="n">render</span> <span class="kn">from</span> <span class="nn">myapp.forms</span> <span class="k">import</span> <span class="n">ArticleForm</span><span class="p">,</span> <span class="n">BookForm</span> <span class="k">def</span> <span class="nf">manage_articles</span><span class="p">(</span><span class="n">request</span><span class="p">):</span> <span class="n">ArticleFormSet</span> <span class="o">=</span> <span class="n">formset_factory</span><span class="p">(</span><span class="n">ArticleForm</span><span class="p">)</span> <span class="n">BookFormSet</span> <span class="o">=</span> <span class="n">formset_factory</span><span class="p">(</span><span class="n">BookForm</span><span class="p">)</span> <span class="k">if</span> <span class="n">request</span><span class="o">.</span><span class="n">method</span> <span class="o">==</span> <span class="s1">'POST'</span><span class="p">:</span> <span class="n">article_formset</span> <span class="o">=</span> <span class="n">ArticleFormSet</span><span class="p">(</span><span class="n">request</span><span class="o">.</span><span class="n">POST</span><span class="p">,</span> <span class="n">request</span><span class="o">.</span><span class="n">FILES</span><span class="p">,</span> <span class="n">prefix</span><span class="o">=</span><span class="s1">'articles'</span><span class="p">)</span> <span class="n">book_formset</span> <span class="o">=</span> <span class="n">BookFormSet</span><span class="p">(</span><span class="n">request</span><span class="o">.</span><span class="n">POST</span><span class="p">,</span> <span class="n">request</span><span class="o">.</span><span class="n">FILES</span><span class="p">,</span> <span class="n">prefix</span><span class="o">=</span><span class="s1">'books'</span><span class="p">)</span> <span class="k">if</span> <span class="n">article_formset</span><span class="o">.</span><span class="n">is_valid</span><span class="p">()</span> <span class="ow">and</span> <span class="n">book_formset</span><span class="o">.</span><span class="n">is_valid</span><span class="p">():</span> <span class="c1"># do something with the cleaned_data on the formsets.</span> <span class="k">pass</span> <span class="k">else</span><span class="p">:</span> <span class="n">article_formset</span> <span class="o">=</span> <span class="n">ArticleFormSet</span><span class="p">(</span><span class="n">prefix</span><span class="o">=</span><span class="s1">'articles'</span><span class="p">)</span> <span class="n">book_formset</span> <span class="o">=</span> <span class="n">BookFormSet</span><span class="p">(</span><span class="n">prefix</span><span class="o">=</span><span class="s1">'books'</span><span class="p">)</span> <span class="k">return</span> <span class="n">render</span><span class="p">(</span><span class="n">request</span><span class="p">,</span> <span class="s1">'manage_articles.html'</span><span class="p">,</span> <span class="p">{</span> <span class="s1">'article_formset'</span><span class="p">:</span> <span class="n">article_formset</span><span class="p">,</span> <span class="s1">'book_formset'</span><span class="p">:</span> <span class="n">book_formset</span><span class="p">,</span> <span class="p">})</span> |
Затем вы должны отобразить формы как обычно. Важно отметить, что вам необходимо передавать префикс как в случае POST, так и в случае не POST, чтобы он правильно отображался и обрабатывался.
Префикс каждого набора форм заменяет префикс формы по умолчанию, который добавляется к атрибутам HTML имени и идентификатора каждого поля.