表单集¶ T0>

BaseFormSet[source]

表单集是同一个页面上多个表单的抽象。 它非常类似于一个数据表格。 假设有下述表单:

>>> from django import forms
>>> class ArticleForm(forms.Form):
...     title = forms.CharField()
...     pub_date = forms.DateField()

你可能希望允许用户一次创建多个Article。 你可以根据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__ 以获得一致的行为。

使用formset 的初始数据

初始数据体现着表单集的主要功能。 如上所述,你可以定义表单的数目。 它表示除了从初始数据生成的表单之外,还要生成多少个额外的表单。 让我们看个例子:

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

上面现在一共有三个表单。 一个是初始数据生成的,还有两个是额外的表单。 还要注意的是,我们传递的初始数据是一个由字典组成的列表。

如果您使用initial来显示表单集,则在处理该表单的提交时,应该传递相同的initial,以便表单集可以检测用户更改哪些表单。 例如,您可能有以下类似的东西:ArticleFormSet(request.POST, initial = [...])

限制表单的最大数量

formset_factory()max_num 参数 ,给予你限制表单集展示表单个数的能力

>>> 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的值 比已经在初始化数据中存在的条目数目多的话, max_num对应个数的额外空表单将会被添加到表单集, 只要表单总数不超过 extra. 例如,如果initialextra=2,并且用一个max_num=2项初始化表单集,将显示空白表单。

假如初始化数据的条目超过 max_num的值, 所有初始化数据表单都会被展现并且忽视 max_num值的限定 ,而且不会有额外的表单被呈现。 比如, 如果extra=3max_num=1 并且表单集由两个初始化条蜜,那么两个带有初始化数据的表单将被呈现。

max_num 的值为 None (默认值) 等同于限制了一个比较高的展现表单数目(1000个). 实际上就是等同于没限制.

默认的, max_num 只影响了表单的数目展示,但不影响验证. 假如 max_num 传给了 formset_factory(), 然后 validate_max=True才将会影响验证. validate_max

表单验证

表单集的验证几乎和 一般的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

我们没有传递任何数据到formset,导致一个有效的形式。 表单集足够聪明,可以忽略未更改的其他表单。 如果我们提供无效的文章:

>>> 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 是一个列表, 他包含的错误信息正好与表单集内的表单一一对应 错误检查会在两个表单中分别执行,被预见的错误出现错误列表的第二项

就像使用正常的Form一样,表单集的表单中的每个字段都可能包含HTML属性,例如用于浏览器验证的maxlength 但是,formets的表单域不会包含required属性,因为添加和删除表单时验证可能不正确。

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

我们也可以检查表单数据是否从初始值发生了变化 (i.e. the form was sent without any data):

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

了解ManagementForm

你也许已经注意到了那些附加的数据 (form-MAX_NUM_FORMS, form-TOTAL_FORMS and form-INITIAL_FORMS) 他们是必要的,且必须位于表单集数据的最上方 这些必须传递给ManagementForm. ManagementFormThis 用于管理表单集中的表单. 如果你不提供这些数据,将会触发异常

>>> 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添加新表单,则应该增加此表单中的计数字段。 On the other hand, if you are using JavaScript to allow deletion of existing objects, then you need to ensure the ones being removed are properly marked for deletion by including form-#-DELETE in the POST data. 期望所有形式存在于POST数据中。

管理表单可用作表单集本身的属性。 在模板中呈现表单集时,您可以通过呈现{{ my_formset.management_form }} t0>(替换您的formset的名称适当)。

total_form_countinitial_form_count

initial_form_count有一些与total_form_countBaseFormSetManagementForm密切相关的方法。

total_form_count返回此表单集中的表单总数。 initial_form_count返回Formset中预填充的表单数,也用于确定需要多少表单。 你可能永远不需要重写这些方法,所以请确保你明白他们做什么之前这样做。

empty_form

__prefix__提供了一个附加属性BaseFormSet,它返回一个前缀为empty_form的表单实例,以便于使用JavaScript的动态表单。

自定义表单验证

一个formset有一个类似于Form类的clean方法。 这是您定义自己的验证,在formset级别工作:

>>> 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方法被调用后,调用formset Form.clean方法。 将使用表单集上的non_form_errors()方法找到错误。

验证表单集中的表单数

Django 提供了两种方法去检查表单能够提交的最大数和最小数, 应用如果需要更多的关于提交数量的自定义验证逻辑,应该使用自定义表单击验证

validate_max

I如果max_num 被提交给 formset_factory(), validation 将在数据集中检查被提交表单的数量, 减去被标记删除的, 必须小于等于validate_max=True.

>>> 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.']

max_num validates 将会对validate_max=True 严格限制,即使提供的初始数据超过 max_num 而导致其无效

Regardless of validate_max, if the number of forms in a data set exceeds max_num by more than 1000, then the form will fail to validate as if validate_max were set, and additionally only the first 1000 forms above max_num will be validated. 剩余部分将被完全截断。 这是为了防止使用伪造的POST请求的内存耗尽攻击。

validate_min

如果min_num被传递到formset_factory(),验证也将检查数据集中的表格数量减去那些被标记为删除的表格数量大于或等于到validate_min=True

>>> 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_ordercan_delete 来实现表单集中表单的排序和删除。

can_order

BaseFormSet。 can_order T0> ¶ T1>

默认值: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 T0> ¶ T1>

默认值: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), 对像将不会被自动删除。 你需要调用formset.deleted_objects每个对像的 delete() 来真正删除他们。

>>> instances = formset.save(commit=False)
>>> for obj in formset.deleted_objects:
...     obj.delete()

另一方面,如果你使用一个简单的FormSet,那么你可以处理formset.deleted_forms,也许在你的formset的save()

向formset 添加附加字段

如果你想往表单集中添加额外的字段,是十分容易完成的, 表单集的基类(BaseFormSet)提供了 add_fields 方法。 可以简单的通过重写这个方法来添加你自己的字段,甚至重新定义order和deletion字段的方法和属性:

>>> 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也可能取决于具体的窗体实例。 formset基类提供了一个get_form_kwargs方法。 该方法采用单个参数 - 表单中的表单的索引。 empty_form的索引为None

>>> 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 类一样简单, 唯一要做的就是确信你在模板中处理表单。 让我们看一个简单视图:

from django.forms import formset_factory
from django.shortcuts import render
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(request, '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_deletecan_order

如果手动在模板中渲染字段,则可以使用{{ form.DELETE }}呈现can_delete参数/ T5> T2>:

<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 t4> }}

在视图中使用多个表单集

可以在视图中使用多个表单集, 表单集从表单中借鉴了很多方法 你可以使用 prefix 给每个表单字段添加前缀,以允许多个字段传递给视图,而不发生命名冲突 让我们看看可以怎么做

from django.forms import formset_factory
from django.shortcuts import render
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(request, 'manage_articles.html', {
        'article_formset': article_formset,
        'book_formset': book_formset,
    })

你可以以正常的方式渲染模板。 记住 prefix 在POST请求和非POST 请求中均需设置,以便他能渲染和执行正确