{"title":"从模型创建表单","version":"5.0","locale":"zh-hans","docname":"topics/forms/modelforms","url":"/zh-hans/5.0/topics/forms/modelforms/","canonical":"https://djangodocs.dev/zh-hans/5.0/topics/forms/modelforms/","summary":"如果您正在构建一个数据库驱动的应用程序，那么您很有可能会用到与Django模型密切相关的表单。","html":"<h1>从模型创建表单<a class=\"heading-anchor\" href=\"#creating-forms-from-models\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h1>\n<section id=\"modelform\">\n<h2><code class=\"docutils literal notranslate\">ModelForm</code><a class=\"heading-anchor\" href=\"#modelform\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<dl class=\"py class\">\n<dt class=\"sig sig-object py\" id=\"django.forms.ModelForm\">\n<em class=\"property\"><span class=\"k\">class</span> </em><span class=\"sig-name descname\">ModelForm</span><a class=\"heading-anchor\" href=\"#django.forms.ModelForm\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd></dd></dl>\n\n<p>如果您正在构建一个数据库驱动的应用程序，那么您很有可能会用到与Django模型密切相关的表单。例如，您可能有一个 <code class=\"docutils literal notranslate\">BlogComment</code> 模型，并且您想创建一个让用户提交评论的表单。在这种情况下，在表单中定义字段类型是多余的，因为您已经在模型中定义了字段。</p>\n<p>因此，Django 提供了一个辅助类让你可以从一个 Django 模型创建一个 <code class=\"docutils literal notranslate\">Form</code> 类。</p>\n<p>例如：</p>\n<div class=\"code-block\" data-language=\"pycon\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python console</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python console code\"><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"kn\">from</span> <span class=\"nn\">django.forms</span> <span class=\"kn\">import</span> ModelForm\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"kn\">from</span> <span class=\"nn\">myapp.models</span> <span class=\"kn\">import</span> Article\n\n<span class=\"go\"># Create the form class.</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"k\">class</span> <span class=\"nc\">ArticleForm</span><span class=\"p\">(</span>ModelForm<span class=\"p\">):</span>\n<span class=\"gp\">... </span>    <span class=\"k\">class</span> <span class=\"nc\">Meta</span><span class=\"p\">:</span>\n<span class=\"gp\">... </span>        model <span class=\"o\">=</span> Article\n<span class=\"gp\">... </span>        fields <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"s2\">&quot;pub_date&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;headline&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;content&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;reporter&quot;</span><span class=\"p\">]</span>\n<span class=\"gp\">...</span>\n\n<span class=\"go\"># Creating a form to add an article.</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>form <span class=\"o\">=</span> ArticleForm<span class=\"p\">()</span>\n\n<span class=\"go\"># Creating a form to change an existing article.</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>article <span class=\"o\">=</span> Article<span class=\"o\">.</span>objects<span class=\"o\">.</span>get<span class=\"p\">(</span>pk<span class=\"o\">=</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>form <span class=\"o\">=</span> ArticleForm<span class=\"p\">(</span>instance<span class=\"o\">=</span>article<span class=\"p\">)</span>\n</code></pre></div>\n<section id=\"field-types\">\n<h3>字段类型<a class=\"heading-anchor\" href=\"#field-types\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>生成的 <code class=\"docutils literal notranslate\">Form</code> 类将按照 <code class=\"docutils literal notranslate\">fields</code> 属性中指定的顺序为每个指定的模型字段设置一个表单字段。</p>\n<p>每个模型字段都有一个对应的默认表单字段。例如，模型中的 <code class=\"docutils literal notranslate\">CharField</code> 在表单中被表现为 <code class=\"docutils literal notranslate\">CharField</code> 。 <code class=\"docutils literal notranslate\">ManyToManyField</code> 则表现为 <code class=\"docutils literal notranslate\">MultipleChoiceField</code> 。以下是完整的转化清单：</p>\n<div class=\"table-scroll\" role=\"region\" tabindex=\"0\" aria-label=\"Table\"><table class=\"docutils align-default\">\n<thead>\n<tr class=\"row-odd\"><th class=\"head\"><p>模型字段</p></th>\n<th class=\"head\"><p>表单字段</p></th>\n</tr>\n</thead>\n<tbody>\n<tr class=\"row-even\"><td><p><a class=\"reference internal\" href=\"/zh-hans/5.0/ref/models/fields/#django.db.models.AutoField\" title=\"django.db.models.AutoField\"><code class=\"xref py py-class docutils literal notranslate\">AutoField</code></a></p></td>\n<td><p>不呈现在表单中</p></td>\n</tr>\n<tr class=\"row-odd\"><td><p><a class=\"reference internal\" href=\"/zh-hans/5.0/ref/models/fields/#django.db.models.BigAutoField\" title=\"django.db.models.BigAutoField\"><code class=\"xref py py-class docutils literal notranslate\">BigAutoField</code></a></p></td>\n<td><p>不呈现在表单中</p></td>\n</tr>\n<tr class=\"row-even\"><td><p><a class=\"reference internal\" href=\"/zh-hans/5.0/ref/models/fields/#django.db.models.BigIntegerField\" title=\"django.db.models.BigIntegerField\"><code class=\"xref py py-class docutils literal notranslate\">BigIntegerField</code></a></p></td>\n<td><p><a class=\"reference internal\" href=\"/zh-hans/5.0/ref/forms/fields/#django.forms.IntegerField\" title=\"django.forms.IntegerField\"><code class=\"xref py py-class docutils literal notranslate\">IntegerField</code></a> 将 <code class=\"docutils literal notranslate\">min_value</code> 设置为-9223372036854775808，将 <code class=\"docutils literal notranslate\">max_value</code> 设置为9223372036854775807。</p></td>\n</tr>\n<tr class=\"row-odd\"><td><p><a class=\"reference internal\" href=\"/zh-hans/5.0/ref/models/fields/#django.db.models.BinaryField\" title=\"django.db.models.BinaryField\"><code class=\"xref py py-class docutils literal notranslate\">BinaryField</code></a></p></td>\n<td><p><a class=\"reference internal\" href=\"/zh-hans/5.0/ref/forms/fields/#django.forms.CharField\" title=\"django.forms.CharField\"><code class=\"xref py py-class docutils literal notranslate\">CharField</code></a> ，如果在模型字段上的 <a class=\"reference internal\" href=\"/zh-hans/5.0/ref/models/fields/#django.db.models.Field.editable\" title=\"django.db.models.Field.editable\"><code class=\"xref py py-attr docutils literal notranslate\">editable</code></a> 被设置为 <code class=\"docutils literal notranslate\">True</code> ，则不在表单中显示。</p></td>\n</tr>\n<tr class=\"row-even\"><td><p><a class=\"reference internal\" href=\"/zh-hans/5.0/ref/models/fields/#django.db.models.BooleanField\" title=\"django.db.models.BooleanField\"><code class=\"xref py py-class docutils literal notranslate\">BooleanField</code></a></p></td>\n<td><p><a class=\"reference internal\" href=\"/zh-hans/5.0/ref/forms/fields/#django.forms.BooleanField\" title=\"django.forms.BooleanField\"><code class=\"xref py py-class docutils literal notranslate\">BooleanField</code></a>, 或 <a class=\"reference internal\" href=\"/zh-hans/5.0/ref/forms/fields/#django.forms.NullBooleanField\" title=\"django.forms.NullBooleanField\"><code class=\"xref py py-class docutils literal notranslate\">NullBooleanField</code></a> （如果 <code class=\"docutils literal notranslate\">null=True</code> ）。</p></td>\n</tr>\n<tr class=\"row-odd\"><td><p><a class=\"reference internal\" href=\"/zh-hans/5.0/ref/models/fields/#django.db.models.CharField\" title=\"django.db.models.CharField\"><code class=\"xref py py-class docutils literal notranslate\">CharField</code></a></p></td>\n<td><p><a class=\"reference internal\" href=\"/zh-hans/5.0/ref/forms/fields/#django.forms.CharField\" title=\"django.forms.CharField\"><code class=\"xref py py-class docutils literal notranslate\">CharField</code></a> 将 <code class=\"docutils literal notranslate\">max_length</code> 设置为模型字段的 <code class=\"docutils literal notranslate\">max_length</code> ，如果模型中设置了 <code class=\"docutils literal notranslate\">null=True</code> ，会将 <a class=\"reference internal\" href=\"/zh-hans/5.0/ref/forms/fields/#django.forms.CharField.empty_value\" title=\"django.forms.CharField.empty_value\"><code class=\"xref py py-attr docutils literal notranslate\">empty_value</code></a> 设置为 <code class=\"docutils literal notranslate\">None</code> 。</p></td>\n</tr>\n<tr class=\"row-even\"><td><p><a class=\"reference internal\" href=\"/zh-hans/5.0/ref/models/fields/#django.db.models.DateField\" title=\"django.db.models.DateField\"><code class=\"xref py py-class docutils literal notranslate\">DateField</code></a></p></td>\n<td><p><a class=\"reference internal\" href=\"/zh-hans/5.0/ref/forms/fields/#django.forms.DateField\" title=\"django.forms.DateField\"><code class=\"xref py py-class docutils literal notranslate\">DateField</code></a></p></td>\n</tr>\n<tr class=\"row-odd\"><td><p><a class=\"reference internal\" href=\"/zh-hans/5.0/ref/models/fields/#django.db.models.DateTimeField\" title=\"django.db.models.DateTimeField\"><code class=\"xref py py-class docutils literal notranslate\">DateTimeField</code></a></p></td>\n<td><p><a class=\"reference internal\" href=\"/zh-hans/5.0/ref/forms/fields/#django.forms.DateTimeField\" title=\"django.forms.DateTimeField\"><code class=\"xref py py-class docutils literal notranslate\">DateTimeField</code></a></p></td>\n</tr>\n<tr class=\"row-even\"><td><p><a class=\"reference internal\" href=\"/zh-hans/5.0/ref/models/fields/#django.db.models.DecimalField\" title=\"django.db.models.DecimalField\"><code class=\"xref py py-class docutils literal notranslate\">DecimalField</code></a></p></td>\n<td><p><a class=\"reference internal\" href=\"/zh-hans/5.0/ref/forms/fields/#django.forms.DecimalField\" title=\"django.forms.DecimalField\"><code class=\"xref py py-class docutils literal notranslate\">DecimalField</code></a></p></td>\n</tr>\n<tr class=\"row-odd\"><td><p><a class=\"reference internal\" href=\"/zh-hans/5.0/ref/models/fields/#django.db.models.DurationField\" title=\"django.db.models.DurationField\"><code class=\"xref py py-class docutils literal notranslate\">DurationField</code></a></p></td>\n<td><p><a class=\"reference internal\" href=\"/zh-hans/5.0/ref/forms/fields/#django.forms.DurationField\" title=\"django.forms.DurationField\"><code class=\"xref py py-class docutils literal notranslate\">DurationField</code></a></p></td>\n</tr>\n<tr class=\"row-even\"><td><p><a class=\"reference internal\" href=\"/zh-hans/5.0/ref/models/fields/#django.db.models.EmailField\" title=\"django.db.models.EmailField\"><code class=\"xref py py-class docutils literal notranslate\">EmailField</code></a></p></td>\n<td><p><a class=\"reference internal\" href=\"/zh-hans/5.0/ref/forms/fields/#django.forms.EmailField\" title=\"django.forms.EmailField\"><code class=\"xref py py-class docutils literal notranslate\">EmailField</code></a></p></td>\n</tr>\n<tr class=\"row-odd\"><td><p><a class=\"reference internal\" href=\"/zh-hans/5.0/ref/models/fields/#django.db.models.FileField\" title=\"django.db.models.FileField\"><code class=\"xref py py-class docutils literal notranslate\">FileField</code></a></p></td>\n<td><p><a class=\"reference internal\" href=\"/zh-hans/5.0/ref/forms/fields/#django.forms.FileField\" title=\"django.forms.FileField\"><code class=\"xref py py-class docutils literal notranslate\">FileField</code></a></p></td>\n</tr>\n<tr class=\"row-even\"><td><p><a class=\"reference internal\" href=\"/zh-hans/5.0/ref/models/fields/#django.db.models.FilePathField\" title=\"django.db.models.FilePathField\"><code class=\"xref py py-class docutils literal notranslate\">FilePathField</code></a></p></td>\n<td><p><a class=\"reference internal\" href=\"/zh-hans/5.0/ref/forms/fields/#django.forms.FilePathField\" title=\"django.forms.FilePathField\"><code class=\"xref py py-class docutils literal notranslate\">FilePathField</code></a></p></td>\n</tr>\n<tr class=\"row-odd\"><td><p><a class=\"reference internal\" href=\"/zh-hans/5.0/ref/models/fields/#django.db.models.FloatField\" title=\"django.db.models.FloatField\"><code class=\"xref py py-class docutils literal notranslate\">FloatField</code></a></p></td>\n<td><p><a class=\"reference internal\" href=\"/zh-hans/5.0/ref/forms/fields/#django.forms.FloatField\" title=\"django.forms.FloatField\"><code class=\"xref py py-class docutils literal notranslate\">FloatField</code></a></p></td>\n</tr>\n<tr class=\"row-even\"><td><p><a class=\"reference internal\" href=\"/zh-hans/5.0/ref/models/fields/#django.db.models.ForeignKey\" title=\"django.db.models.ForeignKey\"><code class=\"xref py py-class docutils literal notranslate\">ForeignKey</code></a></p></td>\n<td><p><a class=\"reference internal\" href=\"/zh-hans/5.0/ref/forms/fields/#django.forms.ModelChoiceField\" title=\"django.forms.ModelChoiceField\"><code class=\"xref py py-class docutils literal notranslate\">ModelChoiceField</code></a> （见下文）</p></td>\n</tr>\n<tr class=\"row-odd\"><td><p><a class=\"reference internal\" href=\"/zh-hans/5.0/ref/models/fields/#django.db.models.ImageField\" title=\"django.db.models.ImageField\"><code class=\"xref py py-class docutils literal notranslate\">ImageField</code></a></p></td>\n<td><p><a class=\"reference internal\" href=\"/zh-hans/5.0/ref/forms/fields/#django.forms.ImageField\" title=\"django.forms.ImageField\"><code class=\"xref py py-class docutils literal notranslate\">ImageField</code></a></p></td>\n</tr>\n<tr class=\"row-even\"><td><p><a class=\"reference internal\" href=\"/zh-hans/5.0/ref/models/fields/#django.db.models.IntegerField\" title=\"django.db.models.IntegerField\"><code class=\"xref py py-class docutils literal notranslate\">IntegerField</code></a></p></td>\n<td><p><a class=\"reference internal\" href=\"/zh-hans/5.0/ref/forms/fields/#django.forms.IntegerField\" title=\"django.forms.IntegerField\"><code class=\"xref py py-class docutils literal notranslate\">IntegerField</code></a></p></td>\n</tr>\n<tr class=\"row-odd\"><td><p><code class=\"docutils literal notranslate\">IPAddressField</code></p></td>\n<td><p><code class=\"docutils literal notranslate\">IPAddressField</code></p></td>\n</tr>\n<tr class=\"row-even\"><td><p><a class=\"reference internal\" href=\"/zh-hans/5.0/ref/models/fields/#django.db.models.GenericIPAddressField\" title=\"django.db.models.GenericIPAddressField\"><code class=\"xref py py-class docutils literal notranslate\">GenericIPAddressField</code></a></p></td>\n<td><p><a class=\"reference internal\" href=\"/zh-hans/5.0/ref/forms/fields/#django.forms.GenericIPAddressField\" title=\"django.forms.GenericIPAddressField\"><code class=\"xref py py-class docutils literal notranslate\">GenericIPAddressField</code></a></p></td>\n</tr>\n<tr class=\"row-odd\"><td><p><a class=\"reference internal\" href=\"/zh-hans/5.0/ref/models/fields/#django.db.models.JSONField\" title=\"django.db.models.JSONField\"><code class=\"xref py py-class docutils literal notranslate\">JSONField</code></a></p></td>\n<td><p><a class=\"reference internal\" href=\"/zh-hans/5.0/ref/forms/fields/#django.forms.JSONField\" title=\"django.forms.JSONField\"><code class=\"xref py py-class docutils literal notranslate\">JSONField</code></a></p></td>\n</tr>\n<tr class=\"row-even\"><td><p><a class=\"reference internal\" href=\"/zh-hans/5.0/ref/models/fields/#django.db.models.ManyToManyField\" title=\"django.db.models.ManyToManyField\"><code class=\"xref py py-class docutils literal notranslate\">ManyToManyField</code></a></p></td>\n<td><p><a class=\"reference internal\" href=\"/zh-hans/5.0/ref/forms/fields/#django.forms.ModelMultipleChoiceField\" title=\"django.forms.ModelMultipleChoiceField\"><code class=\"xref py py-class docutils literal notranslate\">ModelMultipleChoiceField</code></a> （见下文）</p></td>\n</tr>\n<tr class=\"row-odd\"><td><p><a class=\"reference internal\" href=\"/zh-hans/5.0/ref/models/fields/#django.db.models.PositiveBigIntegerField\" title=\"django.db.models.PositiveBigIntegerField\"><code class=\"xref py py-class docutils literal notranslate\">PositiveBigIntegerField</code></a></p></td>\n<td><p><a class=\"reference internal\" href=\"/zh-hans/5.0/ref/forms/fields/#django.forms.IntegerField\" title=\"django.forms.IntegerField\"><code class=\"xref py py-class docutils literal notranslate\">IntegerField</code></a></p></td>\n</tr>\n<tr class=\"row-even\"><td><p><a class=\"reference internal\" href=\"/zh-hans/5.0/ref/models/fields/#django.db.models.PositiveIntegerField\" title=\"django.db.models.PositiveIntegerField\"><code class=\"xref py py-class docutils literal notranslate\">PositiveIntegerField</code></a></p></td>\n<td><p><a class=\"reference internal\" href=\"/zh-hans/5.0/ref/forms/fields/#django.forms.IntegerField\" title=\"django.forms.IntegerField\"><code class=\"xref py py-class docutils literal notranslate\">IntegerField</code></a></p></td>\n</tr>\n<tr class=\"row-odd\"><td><p><a class=\"reference internal\" href=\"/zh-hans/5.0/ref/models/fields/#django.db.models.PositiveSmallIntegerField\" title=\"django.db.models.PositiveSmallIntegerField\"><code class=\"xref py py-class docutils literal notranslate\">PositiveSmallIntegerField</code></a></p></td>\n<td><p><a class=\"reference internal\" href=\"/zh-hans/5.0/ref/forms/fields/#django.forms.IntegerField\" title=\"django.forms.IntegerField\"><code class=\"xref py py-class docutils literal notranslate\">IntegerField</code></a></p></td>\n</tr>\n<tr class=\"row-even\"><td><p><a class=\"reference internal\" href=\"/zh-hans/5.0/ref/models/fields/#django.db.models.SlugField\" title=\"django.db.models.SlugField\"><code class=\"xref py py-class docutils literal notranslate\">SlugField</code></a></p></td>\n<td><p><a class=\"reference internal\" href=\"/zh-hans/5.0/ref/forms/fields/#django.forms.SlugField\" title=\"django.forms.SlugField\"><code class=\"xref py py-class docutils literal notranslate\">SlugField</code></a></p></td>\n</tr>\n<tr class=\"row-odd\"><td><p><a class=\"reference internal\" href=\"/zh-hans/5.0/ref/models/fields/#django.db.models.SmallAutoField\" title=\"django.db.models.SmallAutoField\"><code class=\"xref py py-class docutils literal notranslate\">SmallAutoField</code></a></p></td>\n<td><p>不呈现在表单中</p></td>\n</tr>\n<tr class=\"row-even\"><td><p><a class=\"reference internal\" href=\"/zh-hans/5.0/ref/models/fields/#django.db.models.SmallIntegerField\" title=\"django.db.models.SmallIntegerField\"><code class=\"xref py py-class docutils literal notranslate\">SmallIntegerField</code></a></p></td>\n<td><p><a class=\"reference internal\" href=\"/zh-hans/5.0/ref/forms/fields/#django.forms.IntegerField\" title=\"django.forms.IntegerField\"><code class=\"xref py py-class docutils literal notranslate\">IntegerField</code></a></p></td>\n</tr>\n<tr class=\"row-odd\"><td><p><a class=\"reference internal\" href=\"/zh-hans/5.0/ref/models/fields/#django.db.models.TextField\" title=\"django.db.models.TextField\"><code class=\"xref py py-class docutils literal notranslate\">TextField</code></a></p></td>\n<td><p><a class=\"reference internal\" href=\"/zh-hans/5.0/ref/forms/fields/#django.forms.CharField\" title=\"django.forms.CharField\"><code class=\"xref py py-class docutils literal notranslate\">CharField</code></a> 设置中 <code class=\"docutils literal notranslate\">widget=forms.Textarea</code></p></td>\n</tr>\n<tr class=\"row-even\"><td><p><a class=\"reference internal\" href=\"/zh-hans/5.0/ref/models/fields/#django.db.models.TimeField\" title=\"django.db.models.TimeField\"><code class=\"xref py py-class docutils literal notranslate\">TimeField</code></a></p></td>\n<td><p><a class=\"reference internal\" href=\"/zh-hans/5.0/ref/forms/fields/#django.forms.TimeField\" title=\"django.forms.TimeField\"><code class=\"xref py py-class docutils literal notranslate\">TimeField</code></a></p></td>\n</tr>\n<tr class=\"row-odd\"><td><p><a class=\"reference internal\" href=\"/zh-hans/5.0/ref/models/fields/#django.db.models.URLField\" title=\"django.db.models.URLField\"><code class=\"xref py py-class docutils literal notranslate\">URLField</code></a></p></td>\n<td><p><a class=\"reference internal\" href=\"/zh-hans/5.0/ref/forms/fields/#django.forms.URLField\" title=\"django.forms.URLField\"><code class=\"xref py py-class docutils literal notranslate\">URLField</code></a></p></td>\n</tr>\n<tr class=\"row-even\"><td><p><a class=\"reference internal\" href=\"/zh-hans/5.0/ref/models/fields/#django.db.models.UUIDField\" title=\"django.db.models.UUIDField\"><code class=\"xref py py-class docutils literal notranslate\">UUIDField</code></a></p></td>\n<td><p><a class=\"reference internal\" href=\"/zh-hans/5.0/ref/forms/fields/#django.forms.UUIDField\" title=\"django.forms.UUIDField\"><code class=\"xref py py-class docutils literal notranslate\">UUIDField</code></a></p></td>\n</tr>\n</tbody>\n</table>\n</div>\n<p>如您所料， <code class=\"docutils literal notranslate\">ForeignKey</code> 和 <code class=\"docutils literal notranslate\">ManyToManyField</code> 模型字段类型是特殊情况：</p>\n<ul class=\"simple\">\n<li><p><code class=\"docutils literal notranslate\">ForeignKey</code> 由 <code class=\"docutils literal notranslate\">django.forms.ModelChoiceField</code> 表示， 它是一个 <code class=\"docutils literal notranslate\">ChoiceField</code> ，其选项是一个模型的 <code class=\"docutils literal notranslate\">QuerySet</code> 。</p></li>\n<li><p><code class=\"docutils literal notranslate\">ManyToManyField</code> 由 <code class=\"docutils literal notranslate\">django.forms.ModelMultipleChoiceField</code> 表示，它是一个 <code class=\"docutils literal notranslate\">MultipleChoiceField</code> ，其选项为一个模型 <code class=\"docutils literal notranslate\">QuerySet</code> 。</p></li>\n</ul>\n<p>另外，每个生成的表单字段的属性设置如下：</p>\n<ul class=\"simple\">\n<li><p>如果模型字段设置了 <code class=\"docutils literal notranslate\">blank=True</code> ，那么表单字段的 <code class=\"docutils literal notranslate\">required</code> 属性被设置为 <code class=\"docutils literal notranslate\">False</code> ，否则 <code class=\"docutils literal notranslate\">required=True</code> 。</p></li>\n<li><p>表单字段的 <code class=\"docutils literal notranslate\">label</code> 设置为模型字段的 <code class=\"docutils literal notranslate\">verbose_name</code> ，并且首字母大写。</p></li>\n<li><p>表单字段的 <code class=\"docutils literal notranslate\">help_text</code> 设置为模型字段的 <code class=\"docutils literal notranslate\">help_text</code> 。</p></li>\n<li><p>如果模型字段设置了 <code class=\"docutils literal notranslate\">choices</code> ，那么表单字段的 <code class=\"docutils literal notranslate\">widget</code> 会被设置为 <code class=\"docutils literal notranslate\">Select</code> ，其选项来自模型字段的 <code class=\"docutils literal notranslate\">choices</code> 。这些选项通常包含一个默认选中的空选项。如果字段设置了必填，则会强制用户进行选择。如果模型字段设置了 <code class=\"docutils literal notranslate\">blank=False</code> 以及一个明确的 <code class=\"docutils literal notranslate\">default</code> 值，则表单字段中不会包含空选项（默认会选中 <code class=\"docutils literal notranslate\">default</code> 值）。</p></li>\n</ul>\n<p>最后，请注意，您可以覆盖给定模型字段对应的表单字段。参见下文  <a class=\"reference internal\" href=\"#overriding-the-default-fields\">覆盖默认字段</a> 。</p>\n</section>\n<section id=\"a-full-example\">\n<h3>一个完整的例子<a class=\"heading-anchor\" href=\"#a-full-example\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>思考下下面这组模型：</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"kn\">from</span> <span class=\"nn\">django.db</span> <span class=\"kn\">import</span> models\n<span class=\"kn\">from</span> <span class=\"nn\">django.forms</span> <span class=\"kn\">import</span> ModelForm\n\nTITLE_CHOICES <span class=\"o\">=</span> <span class=\"p\">{</span>\n    <span class=\"s2\">&quot;MR&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;Mr.&quot;</span><span class=\"p\">,</span>\n    <span class=\"s2\">&quot;MRS&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;Mrs.&quot;</span><span class=\"p\">,</span>\n    <span class=\"s2\">&quot;MS&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;Ms.&quot;</span><span class=\"p\">,</span>\n<span class=\"p\">}</span>\n\n\n<span class=\"k\">class</span> <span class=\"nc\">Author</span><span class=\"p\">(</span>models<span class=\"o\">.</span>Model<span class=\"p\">):</span>\n    name <span class=\"o\">=</span> models<span class=\"o\">.</span>CharField<span class=\"p\">(</span>max_length<span class=\"o\">=</span><span class=\"mi\">100</span><span class=\"p\">)</span>\n    title <span class=\"o\">=</span> models<span class=\"o\">.</span>CharField<span class=\"p\">(</span>max_length<span class=\"o\">=</span><span class=\"mi\">3</span><span class=\"p\">,</span> choices<span class=\"o\">=</span>TITLE_CHOICES<span class=\"p\">)</span>\n    birth_date <span class=\"o\">=</span> models<span class=\"o\">.</span>DateField<span class=\"p\">(</span>blank<span class=\"o\">=</span><span class=\"kc\">True</span><span class=\"p\">,</span> null<span class=\"o\">=</span><span class=\"kc\">True</span><span class=\"p\">)</span>\n\n    <span class=\"k\">def</span> <span class=\"fm\">__str__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"k\">return</span> <span class=\"bp\">self</span><span class=\"o\">.</span>name\n\n\n<span class=\"k\">class</span> <span class=\"nc\">Book</span><span class=\"p\">(</span>models<span class=\"o\">.</span>Model<span class=\"p\">):</span>\n    name <span class=\"o\">=</span> models<span class=\"o\">.</span>CharField<span class=\"p\">(</span>max_length<span class=\"o\">=</span><span class=\"mi\">100</span><span class=\"p\">)</span>\n    authors <span class=\"o\">=</span> models<span class=\"o\">.</span>ManyToManyField<span class=\"p\">(</span>Author<span class=\"p\">)</span>\n\n\n<span class=\"k\">class</span> <span class=\"nc\">AuthorForm</span><span class=\"p\">(</span>ModelForm<span class=\"p\">):</span>\n    <span class=\"k\">class</span> <span class=\"nc\">Meta</span><span class=\"p\">:</span>\n        model <span class=\"o\">=</span> Author\n        fields <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"s2\">&quot;name&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;title&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;birth_date&quot;</span><span class=\"p\">]</span>\n\n\n<span class=\"k\">class</span> <span class=\"nc\">BookForm</span><span class=\"p\">(</span>ModelForm<span class=\"p\">):</span>\n    <span class=\"k\">class</span> <span class=\"nc\">Meta</span><span class=\"p\">:</span>\n        model <span class=\"o\">=</span> Book\n        fields <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"s2\">&quot;name&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;authors&quot;</span><span class=\"p\">]</span>\n</code></pre></div>\n<p>通过这些模型，上面的 <code class=\"docutils literal notranslate\">ModelForm</code> 子类将大致等同于（唯一的区别是 <code class=\"docutils literal notranslate\">save()</code> 方法，这我们稍后会讨论）：</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"kn\">from</span> <span class=\"nn\">django</span> <span class=\"kn\">import</span> forms\n\n\n<span class=\"k\">class</span> <span class=\"nc\">AuthorForm</span><span class=\"p\">(</span>forms<span class=\"o\">.</span>Form<span class=\"p\">):</span>\n    name <span class=\"o\">=</span> forms<span class=\"o\">.</span>CharField<span class=\"p\">(</span>max_length<span class=\"o\">=</span><span class=\"mi\">100</span><span class=\"p\">)</span>\n    title <span class=\"o\">=</span> forms<span class=\"o\">.</span>CharField<span class=\"p\">(</span>\n        max_length<span class=\"o\">=</span><span class=\"mi\">3</span><span class=\"p\">,</span>\n        widget<span class=\"o\">=</span>forms<span class=\"o\">.</span>Select<span class=\"p\">(</span>choices<span class=\"o\">=</span>TITLE_CHOICES<span class=\"p\">),</span>\n    <span class=\"p\">)</span>\n    birth_date <span class=\"o\">=</span> forms<span class=\"o\">.</span>DateField<span class=\"p\">(</span>required<span class=\"o\">=</span><span class=\"kc\">False</span><span class=\"p\">)</span>\n\n\n<span class=\"k\">class</span> <span class=\"nc\">BookForm</span><span class=\"p\">(</span>forms<span class=\"o\">.</span>Form<span class=\"p\">):</span>\n    name <span class=\"o\">=</span> forms<span class=\"o\">.</span>CharField<span class=\"p\">(</span>max_length<span class=\"o\">=</span><span class=\"mi\">100</span><span class=\"p\">)</span>\n    authors <span class=\"o\">=</span> forms<span class=\"o\">.</span>ModelMultipleChoiceField<span class=\"p\">(</span>queryset<span class=\"o\">=</span>Author<span class=\"o\">.</span>objects<span class=\"o\">.</span>all<span class=\"p\">())</span>\n</code></pre></div>\n</section>\n<section id=\"validation-on-a-modelform\">\n<span id=\"validation-on-modelform\"></span><h3>验证 <code class=\"docutils literal notranslate\">ModelForm</code><a class=\"heading-anchor\" href=\"#validation-on-a-modelform\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>验证 <code class=\"docutils literal notranslate\">ModelForm</code> 主要涉及两个步骤：</p>\n<ol class=\"arabic simple\">\n<li><p><a class=\"reference internal\" href=\"/zh-hans/5.0/ref/forms/validation/\"><span class=\"doc\">验证表单</span></a></p></li>\n<li><p><a class=\"reference internal\" href=\"/zh-hans/5.0/ref/models/instances/#validating-objects\"><span class=\"std std-ref\">验证模型实例</span></a></p></li>\n</ol>\n<p>和普通的表单验证一样，模型表单验证在调用 <a class=\"reference internal\" href=\"/zh-hans/5.0/ref/forms/api/#django.forms.Form.is_valid\" title=\"django.forms.Form.is_valid\"><code class=\"xref py py-meth docutils literal notranslate\">is_valid()</code></a> 或访问 <a class=\"reference internal\" href=\"/zh-hans/5.0/ref/forms/api/#django.forms.Form.errors\" title=\"django.forms.Form.errors\"><code class=\"xref py py-attr docutils literal notranslate\">errors</code></a> 属性时隐式触发，在调用 <code class=\"docutils literal notranslate\">full_clean()</code> 时显式触发，尽管在实际应用中你不大会用到后一种方法。</p>\n<p><code class=\"docutils literal notranslate\">模型</code> 验证（ <a class=\"reference internal\" href=\"/zh-hans/5.0/ref/models/instances/#django.db.models.Model.full_clean\" title=\"django.db.models.Model.full_clean\"><code class=\"xref py py-meth docutils literal notranslate\">Model.full_clean()</code></a> ）在表单验证步骤中紧随表单的 <code class=\"docutils literal notranslate\">clean()</code> 方法被调用后触发。</p>\n<aside class=\"admonition admonition-warning\" role=\"note\">\n<p class=\"admonition-title\">Warning</p>\n<p>Clean 过程会以各种方式去修改传递给 <code class=\"docutils literal notranslate\">ModelForm</code> 构造方法的模型实例。例如，模型上的所有日期字段都将转换为实际的日期对象。验证失败可能会使底层模型实例处于不一致状态，因此不推荐对其重用。</p>\n</aside>\n<section id=\"overriding-the-clean-method\">\n<span id=\"overriding-modelform-clean-method\"></span><h4>覆盖 <code class=\"docutils literal notranslate\">clean()</code> 方法<a class=\"heading-anchor\" href=\"#overriding-the-clean-method\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h4>\n<p>您可以重写模型表单上的 <code class=\"docutils literal notranslate\">clean()</code> 方法来提供额外的验证，方式和普通的表单一样。</p>\n<p>访问模型对象对应的表单实例包含一个 <code class=\"docutils literal notranslate\">instance</code> 属性，让它可以访问对应的模型实例。</p>\n<aside class=\"admonition admonition-warning\" role=\"note\">\n<p class=\"admonition-title\">Warning</p>\n<p><code class=\"docutils literal notranslate\">ModelForm.clean()</code> 方法设置了一个标识符，使程序在 <a class=\"reference internal\" href=\"/zh-hans/5.0/ref/models/instances/#validating-objects\"><span class=\"std std-ref\">模型验证</span></a>  这步去验证标记为 <code class=\"docutils literal notranslate\">unique</code> 、 <code class=\"docutils literal notranslate\">unique_together</code> 或 <code class=\"docutils literal notranslate\">unique_for_date|month|year</code> 的模型字段的唯一性。</p>\n<p>如果您想覆盖 <code class=\"docutils literal notranslate\">clean()</code> 方法并保持当前的验证，您必须调用父类的 <code class=\"docutils literal notranslate\">clean()</code> 方法。</p>\n</aside>\n</section>\n<section id=\"interaction-with-model-validation\">\n<h4>与模型验证交互<a class=\"heading-anchor\" href=\"#interaction-with-model-validation\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h4>\n<p>作为验证过程的一部分， <code class=\"docutils literal notranslate\">ModelForm</code> 将调用模型上与表单字段对应的每个字段的 <code class=\"docutils literal notranslate\">clean()</code> 方法。如果您排除了一些模型字段，则验证将不会在这些字段上运行。更多有关字段clean及验证是如何工作的内容，请参阅 <a class=\"reference internal\" href=\"/zh-hans/5.0/ref/forms/validation/\"><span class=\"doc\">表单验证</span></a> 文档。</p>\n<p>模型的 <code class=\"docutils literal notranslate\">clean()</code> 方法会在所有唯一性检查之前被调用。有关模型 <code class=\"docutils literal notranslate\">clean()</code> 钩子的更多信息，请参阅 <a class=\"reference internal\" href=\"/zh-hans/5.0/ref/models/instances/#validating-objects\"><span class=\"std std-ref\">验证对象</span></a> 。</p>\n</section>\n<section id=\"considerations-regarding-model-s-error-messages\">\n<span id=\"considerations-regarding-model-errormessages\"></span><h4>有关模型的 <code class=\"docutils literal notranslate\">error_messages</code> 的注意事项<a class=\"heading-anchor\" href=\"#considerations-regarding-model-s-error-messages\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h4>\n<p>在 <a class=\"reference internal\" href=\"/zh-hans/5.0/ref/forms/fields/#django.forms.Field.error_messages\" title=\"django.forms.Field.error_messages\"><code class=\"xref py py-attr docutils literal notranslate\">表单字段</code></a> 级别或者 <a class=\"reference internal\" href=\"#modelforms-overriding-default-fields\"><span class=\"std std-ref\">表单 Meta</span></a> 级别定义的错误信息优先级总是高于在 <a class=\"reference internal\" href=\"/zh-hans/5.0/ref/models/fields/#django.db.models.Field.error_messages\" title=\"django.db.models.Field.error_messages\"><code class=\"xref py py-attr docutils literal notranslate\">模型字段</code></a> 级别定义的。</p>\n<p>在 <a class=\"reference internal\" href=\"/zh-hans/5.0/ref/models/fields/#django.db.models.Field.error_messages\" title=\"django.db.models.Field.error_messages\"><code class=\"xref py py-attr docutils literal notranslate\">模型字段</code></a> 上定义的错误信息只有在 <a class=\"reference internal\" href=\"/zh-hans/5.0/ref/models/instances/#validating-objects\"><span class=\"std std-ref\">模型验证</span></a> 步骤引发 <code class=\"docutils literal notranslate\">ValidationError</code> 时才会使用，并且没有在表单级定义相应的错误信息。</p>\n<p>您可以通过添加 <a class=\"reference internal\" href=\"/zh-hans/5.0/ref/exceptions/#django.core.exceptions.NON_FIELD_ERRORS\" title=\"django.core.exceptions.NON_FIELD_ERRORS\"><code class=\"xref py py-data docutils literal notranslate\">NON_FIELD_ERRORS</code></a> 键到 <code class=\"docutils literal notranslate\">ModelForm</code> 内部的 <code class=\"docutils literal notranslate\">Meta</code> 类的 <code class=\"docutils literal notranslate\">error_messages</code> 中来覆盖模型验证引发的 <code class=\"docutils literal notranslate\">NON_FIELD_ERRORS</code> 错误信息。</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"kn\">from</span> <span class=\"nn\">django.core.exceptions</span> <span class=\"kn\">import</span> NON_FIELD_ERRORS\n<span class=\"kn\">from</span> <span class=\"nn\">django.forms</span> <span class=\"kn\">import</span> ModelForm\n\n\n<span class=\"k\">class</span> <span class=\"nc\">ArticleForm</span><span class=\"p\">(</span>ModelForm<span class=\"p\">):</span>\n    <span class=\"k\">class</span> <span class=\"nc\">Meta</span><span class=\"p\">:</span>\n        error_messages <span class=\"o\">=</span> <span class=\"p\">{</span>\n            NON_FIELD_ERRORS<span class=\"p\">:</span> <span class=\"p\">{</span>\n                <span class=\"s2\">&quot;unique_together&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;</span><span class=\"si\">%(model_name)s</span><span class=\"s2\">&#39;s </span><span class=\"si\">%(field_labels)s</span><span class=\"s2\"> are not unique.&quot;</span><span class=\"p\">,</span>\n            <span class=\"p\">}</span>\n        <span class=\"p\">}</span>\n</code></pre></div>\n</section>\n</section>\n<section id=\"the-save-method\">\n<span id=\"topics-modelform-save\"></span><h3><code class=\"docutils literal notranslate\">save()</code> 方法<a class=\"heading-anchor\" href=\"#the-save-method\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>每个 <code class=\"docutils literal notranslate\">ModelForm</code> 还有一个 <code class=\"docutils literal notranslate\">save()</code> 方法。此方法根据绑定到表单的数据创建并保存数据库对象。 <code class=\"docutils literal notranslate\">ModelForm</code> 的子类可接受一个现有的模型实例作为关键字参数 <code class=\"docutils literal notranslate\">instance</code> ；如果提供了，则 <code class=\"docutils literal notranslate\">save()</code> 会更新这个实例。如果没有，则 <code class=\"docutils literal notranslate\">save()</code> 会创建一个对应模型的新实例。</p>\n<div class=\"code-block\" data-language=\"pycon\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python console</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python console code\"><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"kn\">from</span> <span class=\"nn\">myapp.models</span> <span class=\"kn\">import</span> Article\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"kn\">from</span> <span class=\"nn\">myapp.forms</span> <span class=\"kn\">import</span> ArticleForm\n\n<span class=\"go\"># Create a form instance from POST data.</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>f <span class=\"o\">=</span> ArticleForm<span class=\"p\">(</span>request<span class=\"o\">.</span>POST<span class=\"p\">)</span>\n\n<span class=\"go\"># Save a new Article object from the form&#39;s data.</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>new_article <span class=\"o\">=</span> f<span class=\"o\">.</span>save<span class=\"p\">()</span>\n\n<span class=\"go\"># Create a form to edit an existing Article, but use</span>\n<span class=\"go\"># POST data to populate the form.</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>a <span class=\"o\">=</span> Article<span class=\"o\">.</span>objects<span class=\"o\">.</span>get<span class=\"p\">(</span>pk<span class=\"o\">=</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>f <span class=\"o\">=</span> ArticleForm<span class=\"p\">(</span>request<span class=\"o\">.</span>POST<span class=\"p\">,</span> instance<span class=\"o\">=</span>a<span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>f<span class=\"o\">.</span>save<span class=\"p\">()</span>\n</code></pre></div>\n<p>请注意，如果表单 <a class=\"reference internal\" href=\"#validation-on-modelform\"><span class=\"std std-ref\">尚未验证</span></a> ，调用 <code class=\"docutils literal notranslate\">save()</code> 将通过检查 <code class=\"docutils literal notranslate\">form.errors</code> 来实现验证。如果表单验证不过，则会引发 <code class=\"docutils literal notranslate\">ValueError</code> —— 比如，如果 <code class=\"docutils literal notranslate\">form.errors</code> 返回 <code class=\"docutils literal notranslate\">True</code> 。</p>\n<p>如果一个可选字段没有出现在表单的数据中，并且您给这个模型字段设置了 <a class=\"reference internal\" href=\"/zh-hans/5.0/ref/models/fields/#django.db.models.Field.default\" title=\"django.db.models.Field.default\"><code class=\"xref py py-attr docutils literal notranslate\">default</code></a> ，那么对应的模型实例会使用这个值作为结果。此行为不适用于使用以下组件的字段： <a class=\"reference internal\" href=\"/zh-hans/5.0/ref/forms/widgets/#django.forms.CheckboxInput\" title=\"django.forms.CheckboxInput\"><code class=\"xref py py-class docutils literal notranslate\">CheckboxInput</code></a> 、 <a class=\"reference internal\" href=\"/zh-hans/5.0/ref/forms/widgets/#django.forms.CheckboxSelectMultiple\" title=\"django.forms.CheckboxSelectMultiple\"><code class=\"xref py py-class docutils literal notranslate\">CheckboxSelectMultiple</code></a> 或者 <a class=\"reference internal\" href=\"/zh-hans/5.0/ref/forms/widgets/#django.forms.SelectMultiple\" title=\"django.forms.SelectMultiple\"><code class=\"xref py py-class docutils literal notranslate\">SelectMultiple</code></a> （或者所有其 <a class=\"reference internal\" href=\"/zh-hans/5.0/ref/forms/widgets/#django.forms.Widget.value_omitted_from_data\" title=\"django.forms.Widget.value_omitted_from_data\"><code class=\"xref py py-meth docutils literal notranslate\">value_omitted_from_data()</code></a> 方法总是返回 <code class=\"docutils literal notranslate\">False</code> 的组件），因为未勾选的复选框和未选中的 <code class=\"docutils literal notranslate\">&lt;select multiple&gt;</code> 不会出现在HTML表单提交的数据中。如果您正在设计API并且希望使用这些组件之一的字段有默认回退行为，请使用自定义表单字段或组件。</p>\n<p><code class=\"docutils literal notranslate\">save()</code> 方法接受一个可选参数 <code class=\"docutils literal notranslate\">commit</code> ，它的值是 <code class=\"docutils literal notranslate\">True</code> 或者 <code class=\"docutils literal notranslate\">False</code> 。如果调用 <code class=\"docutils literal notranslate\">save()</code> 的时候使用 <code class=\"docutils literal notranslate\">commit=False</code> ，那么它会返回一个尚未保存到数据库的对象。在这种情况下，需要您自己在生成的模型实例上调用 <code class=\"docutils literal notranslate\">save()</code> 。如果要在保存对象之前对对象执行自定义操作，或者要使用其中一个专用的 <a class=\"reference internal\" href=\"/zh-hans/5.0/ref/models/instances/#ref-models-force-insert\"><span class=\"std std-ref\">模型保存选项</span></a> ，这很有用。 <code class=\"docutils literal notranslate\">commit</code> 的值默认为 <code class=\"docutils literal notranslate\">True</code> 。</p>\n<p>另一个使用 <code class=\"docutils literal notranslate\">commit=False</code> 的作用，您可以在模型与另一个模型有多对多关系的时候看到。如果您的模型具有多对多关系，并且在保存表单时指定了 <code class=\"docutils literal notranslate\">commit=False</code> ，Django无法立即保存多对多关系的表单数据。这是因为实例的多对多数据只有实例在数据库中存在时才能保存。</p>\n<p>要解决这个问题，Django会在您每次使用 <code class=\"docutils literal notranslate\">commit=False</code> 保存表单时，向 <code class=\"docutils literal notranslate\">ModelForm</code> 子类添加一个 <code class=\"docutils literal notranslate\">save_m2m()</code> 方法。在您手动保存表单生成的实例后，可以调用 <code class=\"docutils literal notranslate\">save_m2m()</code> 来保存多对多的表单数据。例如：</p>\n<div class=\"code-block\" data-language=\"pycon\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python console</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python console code\"><code><span class=\"go\"># Create a form instance with POST data.</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>f <span class=\"o\">=</span> AuthorForm<span class=\"p\">(</span>request<span class=\"o\">.</span>POST<span class=\"p\">)</span>\n\n<span class=\"go\"># Create, but don&#39;t save the new author instance.</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>new_author <span class=\"o\">=</span> f<span class=\"o\">.</span>save<span class=\"p\">(</span>commit<span class=\"o\">=</span><span class=\"kc\">False</span><span class=\"p\">)</span>\n\n<span class=\"go\"># Modify the author in some way.</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>new_author<span class=\"o\">.</span>some_field <span class=\"o\">=</span> <span class=\"s2\">&quot;some_value&quot;</span>\n\n<span class=\"go\"># Save the new instance.</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>new_author<span class=\"o\">.</span>save<span class=\"p\">()</span>\n\n<span class=\"go\"># Now, save the many-to-many data for the form.</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>f<span class=\"o\">.</span>save_m2m<span class=\"p\">()</span>\n</code></pre></div>\n<p>只有在使用 <code class=\"docutils literal notranslate\">save(commit=False)</code> 时才需要调用 <code class=\"docutils literal notranslate\">save_m2m()</code>。当你在表单上使用 <code class=\"docutils literal notranslate\">save()</code> 时，所有数据 -- 包括多对多数据 -- 都会保存，无需任何额外的方法调用。例如：</p>\n<div class=\"code-block\" data-language=\"pycon\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python console</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python console code\"><code><span class=\"go\"># Create a form instance with POST data.</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>a <span class=\"o\">=</span> Author<span class=\"p\">()</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>f <span class=\"o\">=</span> AuthorForm<span class=\"p\">(</span>request<span class=\"o\">.</span>POST<span class=\"p\">,</span> instance<span class=\"o\">=</span>a<span class=\"p\">)</span>\n\n<span class=\"go\"># Create and save the new author instance. There&#39;s no need to do anything else.</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>new_author <span class=\"o\">=</span> f<span class=\"o\">.</span>save<span class=\"p\">()</span>\n</code></pre></div>\n<p>除了  <code class=\"docutils literal notranslate\">save()</code> 和 <code class=\"docutils literal notranslate\">save_m2m()</code> 方法之外，<code class=\"docutils literal notranslate\">ModelForm</code> 与普通的表单工作方式一样。例如，用 <code class=\"docutils literal notranslate\">is_valid()</code> 方法来检查合法性，用 <code class=\"docutils literal notranslate\">is_multipart()</code> 方法来确定表单是否需要multipart文件上传（之后是否必须将 <code class=\"docutils literal notranslate\">request.FILES</code> 传递给表单），等等。更多相关信息，请参阅 <a class=\"reference internal\" href=\"/zh-hans/5.0/ref/forms/api/#binding-uploaded-files\"><span class=\"std std-ref\">将上传的文件绑定到表单中</span></a> 。</p>\n</section>\n<section id=\"selecting-the-fields-to-use\">\n<span id=\"modelforms-selecting-fields\"></span><h3>选择要使用的字段<a class=\"heading-anchor\" href=\"#selecting-the-fields-to-use\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>强烈建议您使用 <code class=\"docutils literal notranslate\">fields</code> 属性来显式设置所有应在表单中编辑的字段。如果不这样做，当一张表单不慎允许用户设置某些字段，尤其是在将新字段添加到模型中时，很容易导致安全问题。根据表单渲染方式的不同，甚至可能不会在网页上显示问题。</p>\n<p>另一种方法是自动包括所有字段，或只删除一些字段。众所周知，这种基本方法的安全性要低得多，并导致主要网站出现严重的漏洞（例如，<a class=\"reference external\" href=\"https://github.blog/2012-03-04-public-key-security-vulnerability-and-mitigation/\">GitHub</a> ）。</p>\n<p>但是，有两种简单的方法保证你不会出现这些安全问题：</p>\n<ol class=\"arabic\">\n<li><p>将 <code class=\"docutils literal notranslate\">fields</code> 属性设置为特殊值 <code class=\"docutils literal notranslate\">'__all__'</code> 以表明需要使用模型中的所有字段。例如：</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"kn\">from</span> <span class=\"nn\">django.forms</span> <span class=\"kn\">import</span> ModelForm\n\n\n<span class=\"k\">class</span> <span class=\"nc\">AuthorForm</span><span class=\"p\">(</span>ModelForm<span class=\"p\">):</span>\n    <span class=\"k\">class</span> <span class=\"nc\">Meta</span><span class=\"p\">:</span>\n        model <span class=\"o\">=</span> Author\n        fields <span class=\"o\">=</span> <span class=\"s2\">&quot;__all__&quot;</span>\n</code></pre></div>\n</li>\n<li><p>将 <code class=\"docutils literal notranslate\">ModelForm</code> 中Meta类的 <code class=\"docutils literal notranslate\">exclude</code> 属性设置为表单中需要排除的字段列表。</p>\n<p>例如：</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"k\">class</span> <span class=\"nc\">PartialAuthorForm</span><span class=\"p\">(</span>ModelForm<span class=\"p\">):</span>\n    <span class=\"k\">class</span> <span class=\"nc\">Meta</span><span class=\"p\">:</span>\n        model <span class=\"o\">=</span> Author\n        exclude <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"s2\">&quot;title&quot;</span><span class=\"p\">]</span>\n</code></pre></div>\n<p>由于 <code class=\"docutils literal notranslate\">Author</code> 模型有三个字段 <code class=\"docutils literal notranslate\">name</code>、 <code class=\"docutils literal notranslate\">title</code> 和 <code class=\"docutils literal notranslate\">birth_date</code> ，上例的结果是字段 <code class=\"docutils literal notranslate\">name</code> 和 <code class=\"docutils literal notranslate\">birth_date</code> 会呈现在表单中。</p>\n</li>\n</ol>\n<p>不管使用哪一种，字段会按模型中定义的顺序在表单中出现， <code class=\"docutils literal notranslate\">ManyToManyField</code> 会排在最后。</p>\n<p>另外，Django有个规则：如果您在模型字段中定义了 <code class=\"docutils literal notranslate\">editable=False</code> ， <em>任何</em> 使用 <code class=\"docutils literal notranslate\">ModelForm</code> 给该模型创建的表单都不会包含这个字段。</p>\n<aside class=\"admonition admonition-note\" role=\"note\">\n<p class=\"admonition-title\">Note</p>\n<p>任何没在上面逻辑中包含的表单字段都会不被表单的 <code class=\"docutils literal notranslate\">save()</code> 方法处理。另外，如果手动将排除的字段添加回表单，它们也不会被模型实例初始化。</p>\n<p>Django会阻止任何尝试保存不完整模型的行为，所以如果模型不允许缺省的字段为空，并且没有为该字段提供缺省值，那么任何尝试用这种字段的 <code class=\"docutils literal notranslate\">ModelForm</code> 的 <code class=\"docutils literal notranslate\">save()</code> 方法都会失败。为了避免这种情况，您必须使用初始值实例化您模型中缺省但又必填的字段：</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code>author <span class=\"o\">=</span> Author<span class=\"p\">(</span>title<span class=\"o\">=</span><span class=\"s2\">&quot;Mr&quot;</span><span class=\"p\">)</span>\nform <span class=\"o\">=</span> PartialAuthorForm<span class=\"p\">(</span>request<span class=\"o\">.</span>POST<span class=\"p\">,</span> instance<span class=\"o\">=</span>author<span class=\"p\">)</span>\nform<span class=\"o\">.</span>save<span class=\"p\">()</span>\n</code></pre></div>\n<p>或者，您可以使用 <code class=\"docutils literal notranslate\">save(commit=False)</code> 然后手动设置其他必填字段：</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code>form <span class=\"o\">=</span> PartialAuthorForm<span class=\"p\">(</span>request<span class=\"o\">.</span>POST<span class=\"p\">)</span>\nauthor <span class=\"o\">=</span> form<span class=\"o\">.</span>save<span class=\"p\">(</span>commit<span class=\"o\">=</span><span class=\"kc\">False</span><span class=\"p\">)</span>\nauthor<span class=\"o\">.</span>title <span class=\"o\">=</span> <span class=\"s2\">&quot;Mr&quot;</span>\nauthor<span class=\"o\">.</span>save<span class=\"p\">()</span>\n</code></pre></div>\n<p>更多关于使用 <code class=\"docutils literal notranslate\">save(commit=False)</code> 的详细内容，请参阅 <a class=\"reference internal\" href=\"#the-save-method\">保存表单章节</a> 。</p>\n</aside>\n</section>\n<section id=\"overriding-the-default-fields\">\n<span id=\"modelforms-overriding-default-fields\"></span><h3>覆盖默认字段<a class=\"heading-anchor\" href=\"#overriding-the-default-fields\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>之前在 <a class=\"reference internal\" href=\"#field-types\">字段类型</a> 表格中介绍的默认字段类型都是相对合适的。如果您的模型中有一个 <code class=\"docutils literal notranslate\">DateField</code> ，您可能希望在表单中将它展示为 <code class=\"docutils literal notranslate\">DateField</code> 。但 <code class=\"docutils literal notranslate\">ModelForm</code> 可以让您灵活地改变给定模型的表单字段。</p>\n<p>要为字段指定自定义组件，请使用内部 <code class=\"docutils literal notranslate\">Meta</code> 类的 <code class=\"docutils literal notranslate\">widgets</code> 属性。它应该是一个映射字段名到组建类或组件实例的字典。</p>\n<p>例如，如果您希望 <code class=\"docutils literal notranslate\">Author</code> 的 <code class=\"docutils literal notranslate\">name</code> 属性的 <code class=\"docutils literal notranslate\">CharField</code> 由 <code class=\"docutils literal notranslate\">&lt;textarea&gt;</code> 代替默认的 <code class=\"docutils literal notranslate\">&lt;input type=&quot;text&quot;&gt;</code> 来表示，您可以重写字段的部件：</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"kn\">from</span> <span class=\"nn\">django.forms</span> <span class=\"kn\">import</span> ModelForm<span class=\"p\">,</span> Textarea\n<span class=\"kn\">from</span> <span class=\"nn\">myapp.models</span> <span class=\"kn\">import</span> Author\n\n\n<span class=\"k\">class</span> <span class=\"nc\">AuthorForm</span><span class=\"p\">(</span>ModelForm<span class=\"p\">):</span>\n    <span class=\"k\">class</span> <span class=\"nc\">Meta</span><span class=\"p\">:</span>\n        model <span class=\"o\">=</span> Author\n        fields <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"s2\">&quot;name&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;title&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;birth_date&quot;</span><span class=\"p\">]</span>\n        widgets <span class=\"o\">=</span> <span class=\"p\">{</span>\n            <span class=\"s2\">&quot;name&quot;</span><span class=\"p\">:</span> Textarea<span class=\"p\">(</span>attrs<span class=\"o\">=</span><span class=\"p\">{</span><span class=\"s2\">&quot;cols&quot;</span><span class=\"p\">:</span> <span class=\"mi\">80</span><span class=\"p\">,</span> <span class=\"s2\">&quot;rows&quot;</span><span class=\"p\">:</span> <span class=\"mi\">20</span><span class=\"p\">}),</span>\n        <span class=\"p\">}</span>\n</code></pre></div>\n<p><code class=\"docutils literal notranslate\">widgets</code> 字典接受任何 widget 实例（例如 <code class=\"docutils literal notranslate\">Textarea(...)</code> ）或类（例如 <code class=\"docutils literal notranslate\">Textarea</code>）。注意，对于具有非空 <code class=\"docutils literal notranslate\">choices</code> 属性的模型字段，<code class=\"docutils literal notranslate\">widgets</code> 字典会被忽略。在这个例子里，你必须覆盖表单字段来使用不同的 widget 。</p>\n<p>同样的，如果您想进一步自定义一个字段，还可以指定内部Meta类的 <code class=\"docutils literal notranslate\">labels</code> 、 <code class=\"docutils literal notranslate\">help_texts</code> 和 <code class=\"docutils literal notranslate\">error_messages</code> 属性。</p>\n<p>例如您想自定义 <code class=\"docutils literal notranslate\">name</code> 字段中所有面向用户的字符文本：</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"kn\">from</span> <span class=\"nn\">django.utils.translation</span> <span class=\"kn\">import</span> gettext_lazy <span class=\"k\">as</span> _\n\n\n<span class=\"k\">class</span> <span class=\"nc\">AuthorForm</span><span class=\"p\">(</span>ModelForm<span class=\"p\">):</span>\n    <span class=\"k\">class</span> <span class=\"nc\">Meta</span><span class=\"p\">:</span>\n        model <span class=\"o\">=</span> Author\n        fields <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"s2\">&quot;name&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;title&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;birth_date&quot;</span><span class=\"p\">]</span>\n        labels <span class=\"o\">=</span> <span class=\"p\">{</span>\n            <span class=\"s2\">&quot;name&quot;</span><span class=\"p\">:</span> _<span class=\"p\">(</span><span class=\"s2\">&quot;Writer&quot;</span><span class=\"p\">),</span>\n        <span class=\"p\">}</span>\n        help_texts <span class=\"o\">=</span> <span class=\"p\">{</span>\n            <span class=\"s2\">&quot;name&quot;</span><span class=\"p\">:</span> _<span class=\"p\">(</span><span class=\"s2\">&quot;Some useful help text.&quot;</span><span class=\"p\">),</span>\n        <span class=\"p\">}</span>\n        error_messages <span class=\"o\">=</span> <span class=\"p\">{</span>\n            <span class=\"s2\">&quot;name&quot;</span><span class=\"p\">:</span> <span class=\"p\">{</span>\n                <span class=\"s2\">&quot;max_length&quot;</span><span class=\"p\">:</span> _<span class=\"p\">(</span><span class=\"s2\">&quot;This writer&#39;s name is too long.&quot;</span><span class=\"p\">),</span>\n            <span class=\"p\">},</span>\n        <span class=\"p\">}</span>\n</code></pre></div>\n<p>你还可以指定 <code class=\"docutils literal notranslate\">field_classes</code> 或 <code class=\"docutils literal notranslate\">formfield_callback</code> 来自定义表单实例化的字段类型。</p>\n<p>例如，如果您想对 <code class=\"docutils literal notranslate\">slug</code> 字段使用 <code class=\"docutils literal notranslate\">MySlugFormField</code> ，您可以这样做：</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"kn\">from</span> <span class=\"nn\">django.forms</span> <span class=\"kn\">import</span> ModelForm\n<span class=\"kn\">from</span> <span class=\"nn\">myapp.models</span> <span class=\"kn\">import</span> Article\n\n\n<span class=\"k\">class</span> <span class=\"nc\">ArticleForm</span><span class=\"p\">(</span>ModelForm<span class=\"p\">):</span>\n    <span class=\"k\">class</span> <span class=\"nc\">Meta</span><span class=\"p\">:</span>\n        model <span class=\"o\">=</span> Article\n        fields <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"s2\">&quot;pub_date&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;headline&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;content&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;reporter&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;slug&quot;</span><span class=\"p\">]</span>\n        field_classes <span class=\"o\">=</span> <span class=\"p\">{</span>\n            <span class=\"s2\">&quot;slug&quot;</span><span class=\"p\">:</span> MySlugFormField<span class=\"p\">,</span>\n        <span class=\"p\">}</span>\n</code></pre></div>\n<p>或者：</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"kn\">from</span> <span class=\"nn\">django.forms</span> <span class=\"kn\">import</span> ModelForm\n<span class=\"kn\">from</span> <span class=\"nn\">myapp.models</span> <span class=\"kn\">import</span> Article\n\n\n<span class=\"k\">def</span> <span class=\"nf\">formfield_for_dbfield</span><span class=\"p\">(</span>db_field<span class=\"p\">,</span> <span class=\"o\">**</span>kwargs<span class=\"p\">):</span>\n    <span class=\"k\">if</span> db_field<span class=\"o\">.</span>name <span class=\"o\">==</span> <span class=\"s2\">&quot;slug&quot;</span><span class=\"p\">:</span>\n        <span class=\"k\">return</span> MySlugFormField<span class=\"p\">()</span>\n    <span class=\"k\">return</span> db_field<span class=\"o\">.</span>formfield<span class=\"p\">(</span><span class=\"o\">**</span>kwargs<span class=\"p\">)</span>\n\n\n<span class=\"k\">class</span> <span class=\"nc\">ArticleForm</span><span class=\"p\">(</span>ModelForm<span class=\"p\">):</span>\n    <span class=\"k\">class</span> <span class=\"nc\">Meta</span><span class=\"p\">:</span>\n        model <span class=\"o\">=</span> Article\n        fields <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"s2\">&quot;pub_date&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;headline&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;content&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;reporter&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;slug&quot;</span><span class=\"p\">]</span>\n        formfield_callback <span class=\"o\">=</span> formfield_for_dbfield\n</code></pre></div>\n<p>最后，如果您想完全控制一个字段（包括它的类型，验证，必填等等），您可以通过声明指定字段来做到这一点，就像在一个普通的 <code class=\"docutils literal notranslate\">Form</code> 中那样声明。</p>\n<p>如果您想指定一个字段的验证器，可以通过声明定义该字段并设置其 <code class=\"docutils literal notranslate\">validators</code> 参数来实现：</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"kn\">from</span> <span class=\"nn\">django.forms</span> <span class=\"kn\">import</span> CharField<span class=\"p\">,</span> ModelForm\n<span class=\"kn\">from</span> <span class=\"nn\">myapp.models</span> <span class=\"kn\">import</span> Article\n\n\n<span class=\"k\">class</span> <span class=\"nc\">ArticleForm</span><span class=\"p\">(</span>ModelForm<span class=\"p\">):</span>\n    slug <span class=\"o\">=</span> CharField<span class=\"p\">(</span>validators<span class=\"o\">=</span><span class=\"p\">[</span>validate_slug<span class=\"p\">])</span>\n\n    <span class=\"k\">class</span> <span class=\"nc\">Meta</span><span class=\"p\">:</span>\n        model <span class=\"o\">=</span> Article\n        fields <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"s2\">&quot;pub_date&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;headline&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;content&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;reporter&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;slug&quot;</span><span class=\"p\">]</span>\n</code></pre></div>\n<aside class=\"admonition admonition-note\" role=\"note\">\n<p class=\"admonition-title\">Note</p>\n<p>当您像这样显式地实例化了一个表单字段，理解 <code class=\"docutils literal notranslate\">ModelForm</code> 和普通  <code class=\"docutils literal notranslate\">Form</code> 的关系很重要。</p>\n<p><code class=\"docutils literal notranslate\">ModelForm</code> 是一个可以自动生成特定字段的 <code class=\"docutils literal notranslate\">Form</code> 。哪些字段可以自动生成取决于 <code class=\"docutils literal notranslate\">Meta</code> 类的内容，以及是否已经被明确定义过。总的来说 <code class=\"docutils literal notranslate\">ModelForm</code>  <strong>仅会</strong> 自动生成表单中 <strong>缺失</strong> 的字段，或者说，没被明确定义的字段。</p>\n<p>声明定义的字段会保持原样，因此，任何对 <code class=\"docutils literal notranslate\">Meta</code> 属性（例如 <code class=\"docutils literal notranslate\">widgets</code> 、 <code class=\"docutils literal notranslate\">labels</code> 、 <code class=\"docutils literal notranslate\">help_texts</code> 或者 <code class=\"docutils literal notranslate\">error_messages</code>）的自定义设置都会被忽略；它们仅适用于自动生成的字段。</p>\n<p>同样，显式定义的字段不会从对应的模型中获取他们的属性（比如 <code class=\"docutils literal notranslate\">max_length</code> 或者 <code class=\"docutils literal notranslate\">required</code>）。如果要保持模型中指定的行为，则必须在声明表单字段时显式设置相关参数。</p>\n<p>例如，假设 <code class=\"docutils literal notranslate\">Article</code> 模型像下面这样：</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"k\">class</span> <span class=\"nc\">Article</span><span class=\"p\">(</span>models<span class=\"o\">.</span>Model<span class=\"p\">):</span>\n    headline <span class=\"o\">=</span> models<span class=\"o\">.</span>CharField<span class=\"p\">(</span>\n        max_length<span class=\"o\">=</span><span class=\"mi\">200</span><span class=\"p\">,</span>\n        null<span class=\"o\">=</span><span class=\"kc\">True</span><span class=\"p\">,</span>\n        blank<span class=\"o\">=</span><span class=\"kc\">True</span><span class=\"p\">,</span>\n        help_text<span class=\"o\">=</span><span class=\"s2\">&quot;Use puns liberally&quot;</span><span class=\"p\">,</span>\n    <span class=\"p\">)</span>\n    content <span class=\"o\">=</span> models<span class=\"o\">.</span>TextField<span class=\"p\">()</span>\n</code></pre></div>\n<p>且您希望对 <code class=\"docutils literal notranslate\">headline</code> 进行自定义验证，在保留指定的 <code class=\"docutils literal notranslate\">blank</code> 和 <code class=\"docutils literal notranslate\">help_text</code> 值同时，您可以像这样定义 <code class=\"docutils literal notranslate\">ArticleForm</code> ：</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"k\">class</span> <span class=\"nc\">ArticleForm</span><span class=\"p\">(</span>ModelForm<span class=\"p\">):</span>\n    headline <span class=\"o\">=</span> MyFormField<span class=\"p\">(</span>\n        max_length<span class=\"o\">=</span><span class=\"mi\">200</span><span class=\"p\">,</span>\n        required<span class=\"o\">=</span><span class=\"kc\">False</span><span class=\"p\">,</span>\n        help_text<span class=\"o\">=</span><span class=\"s2\">&quot;Use puns liberally&quot;</span><span class=\"p\">,</span>\n    <span class=\"p\">)</span>\n\n    <span class=\"k\">class</span> <span class=\"nc\">Meta</span><span class=\"p\">:</span>\n        model <span class=\"o\">=</span> Article\n        fields <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"s2\">&quot;headline&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;content&quot;</span><span class=\"p\">]</span>\n</code></pre></div>\n<p>您必须确保表单字段的类型可用于设置对应模型字段的内容。如果它们不兼容，您会因为没有发生隐式转换而得到一个 <code class=\"docutils literal notranslate\">ValueError</code> 。</p>\n<p>更多有关字段及其参数的内容，请参阅 <a class=\"reference internal\" href=\"/zh-hans/5.0/ref/forms/fields/\"><span class=\"doc\">表单字段文档</span></a> 。</p>\n</aside>\n<aside class=\"version-note version-changed\" data-version=\"4.2\" role=\"note\">\n<p class=\"version-note-title\">Changed in Django 4.2</p><p>添加了 <code class=\"docutils literal notranslate\">Meta.formfield_callback</code> 属性。</p>\n</aside>\n</section>\n<section id=\"enabling-localization-of-fields\">\n<h3>启用对字段的本地化<a class=\"heading-anchor\" href=\"#enabling-localization-of-fields\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>默认情况下， <code class=\"docutils literal notranslate\">ModelForm</code> 中的字段不会本地化他们的数据。要为字段启用本地化，您可以在 <code class=\"docutils literal notranslate\">Meta</code> 类中使用 <code class=\"docutils literal notranslate\">localized_fields</code> 属性。</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"kn\">from</span> <span class=\"nn\">django.forms</span> <span class=\"kn\">import</span> ModelForm\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"kn\">from</span> <span class=\"nn\">myapp.models</span> <span class=\"kn\">import</span> Author\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"k\">class</span> <span class=\"nc\">AuthorForm</span><span class=\"p\">(</span>ModelForm<span class=\"p\">):</span>\n<span class=\"gp\">... </span>    <span class=\"k\">class</span> <span class=\"nc\">Meta</span><span class=\"p\">:</span>\n<span class=\"gp\">... </span>        model <span class=\"o\">=</span> Author\n<span class=\"gp\">... </span>        localized_fields <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"s1\">&#39;birth_date&#39;</span><span class=\"p\">]</span>\n</code></pre></div>\n<p>如果 <code class=\"docutils literal notranslate\">localized_fields</code> 设置为特殊值 <code class=\"docutils literal notranslate\">'__all__'</code> ，则所有字段都将被本地化。</p>\n</section>\n<section id=\"form-inheritance\">\n<h3>表单继承<a class=\"heading-anchor\" href=\"#form-inheritance\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>与基本表单一样，你可以通过继承它们来扩展和重用 <code class=\"docutils literal notranslate\">ModelForms</code>。这在你需要在从模型派生的多个表单中声明额外字段或额外方法的情况下非常有用。例如，使用先前的 <code class=\"docutils literal notranslate\">ArticleForm</code> 类：</p>\n<div class=\"code-block\" data-language=\"pycon\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python console</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python console code\"><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"k\">class</span> <span class=\"nc\">EnhancedArticleForm</span><span class=\"p\">(</span>ArticleForm<span class=\"p\">):</span>\n<span class=\"gp\">... </span>    <span class=\"k\">def</span> <span class=\"nf\">clean_pub_date</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span> <span class=\"o\">...</span>\n<span class=\"gp\">...</span>\n</code></pre></div>\n<p>这会创建一个与 <code class=\"docutils literal notranslate\">ArticleForm</code> 行为相同的表单，除了 <code class=\"docutils literal notranslate\">pub_date</code> 字段会有一些额外的验证和cleaning。</p>\n<p>你还可以继承父类的 <code class=\"docutils literal notranslate\">Meta</code> 内部类，如果你想要更改 <code class=\"docutils literal notranslate\">Meta.fields</code> 或 <code class=\"docutils literal notranslate\">Meta.exclude</code> 列表：</p>\n<div class=\"code-block\" data-language=\"pycon\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python console</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python console code\"><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"k\">class</span> <span class=\"nc\">RestrictedArticleForm</span><span class=\"p\">(</span>EnhancedArticleForm<span class=\"p\">):</span>\n<span class=\"gp\">... </span>    <span class=\"k\">class</span> <span class=\"nc\">Meta</span><span class=\"p\">(</span>ArticleForm<span class=\"o\">.</span>Meta<span class=\"p\">):</span>\n<span class=\"gp\">... </span>        exclude <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"s2\">&quot;body&quot;</span><span class=\"p\">]</span>\n<span class=\"gp\">...</span>\n</code></pre></div>\n<p>这相比 <code class=\"docutils literal notranslate\">EnhancedArticleForm</code> 增加了额外方法，并修改了原始的 <code class=\"docutils literal notranslate\">ArticleForm.Meta</code> 以删除一个字段。</p>\n<p>然而，有几项需要注意。</p>\n<ul>\n<li><p>适用于普通的Python名称解析规则。如果您有多个声明 <code class=\"docutils literal notranslate\">Meta</code> 内部类的基类，就是说如果声明了子类的 <code class=\"docutils literal notranslate\">Meta</code> 就会使用它，否则就用第一个父类的 <code class=\"docutils literal notranslate\">Meta</code> 。</p></li>\n<li><p>可以同时继承 <code class=\"docutils literal notranslate\">Form</code> 和 <code class=\"docutils literal notranslate\">ModelForm</code> ，但是，您必须确保 <code class=\"docutils literal notranslate\">ModelForm</code> 在MRO中出现在首位。这是因为这些类依赖于不同的元类，而一个类只能有一个元类。</p></li>\n<li><p>通过在子类上将名称设置为 <code class=\"docutils literal notranslate\">None</code> ，可以声明性地移除从父类继承的 <code class=\"docutils literal notranslate\">Field</code> 。</p>\n<p>您只能使用这种技术排除父类中声明定义的字段；它不会阻止 <code class=\"docutils literal notranslate\">ModelForm</code> 元类生成默认字段。要排除默认字段，请参阅 <a class=\"reference internal\" href=\"#modelforms-selecting-fields\"><span class=\"std std-ref\">选择要使用的字段</span></a> 。</p>\n</li>\n</ul>\n</section>\n<section id=\"providing-initial-values\">\n<h3>提供初始值<a class=\"heading-anchor\" href=\"#providing-initial-values\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>与常规表单一样，可以通过在实例化表单时指定一个 <code class=\"docutils literal notranslate\">initial</code> 参数来为表单指定初始数据。以这种方式提供的初始值将覆盖表单字段的初始值和附加的模型实例的值。例如：</p>\n<div class=\"code-block\" data-language=\"pycon\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python console</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python console code\"><code><span class=\"gp\">&gt;&gt;&gt; </span>article <span class=\"o\">=</span> Article<span class=\"o\">.</span>objects<span class=\"o\">.</span>get<span class=\"p\">(</span>pk<span class=\"o\">=</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>article<span class=\"o\">.</span>headline\n<span class=\"go\">&#39;My headline&#39;</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>form <span class=\"o\">=</span> ArticleForm<span class=\"p\">(</span>initial<span class=\"o\">=</span><span class=\"p\">{</span><span class=\"s2\">&quot;headline&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;Initial headline&quot;</span><span class=\"p\">},</span> instance<span class=\"o\">=</span>article<span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>form<span class=\"p\">[</span><span class=\"s2\">&quot;headline&quot;</span><span class=\"p\">]</span><span class=\"o\">.</span>value<span class=\"p\">()</span>\n<span class=\"go\">&#39;Initial headline&#39;</span>\n</code></pre></div>\n</section>\n<section id=\"modelform-factory-function\">\n<span id=\"modelforms-factory\"></span><h3>ModelForm的工厂函数<a class=\"heading-anchor\" href=\"#modelform-factory-function\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>你可以使用独立函数 <a class=\"reference internal\" href=\"/zh-hans/5.0/ref/forms/models/#django.forms.models.modelform_factory\" title=\"django.forms.models.modelform_factory\"><code class=\"xref py py-func docutils literal notranslate\">modelform_factory()</code></a> 来从给定的模型创建表单，而不是使用类定义。如果你没有太多自定义需求，这可能会更方便：</p>\n<div class=\"code-block\" data-language=\"pycon\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python console</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python console code\"><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"kn\">from</span> <span class=\"nn\">django.forms</span> <span class=\"kn\">import</span> modelform_factory\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"kn\">from</span> <span class=\"nn\">myapp.models</span> <span class=\"kn\">import</span> Book\n<span class=\"gp\">&gt;&gt;&gt; </span>BookForm <span class=\"o\">=</span> modelform_factory<span class=\"p\">(</span>Book<span class=\"p\">,</span> fields<span class=\"o\">=</span><span class=\"p\">[</span><span class=\"s2\">&quot;author&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;title&quot;</span><span class=\"p\">])</span>\n</code></pre></div>\n<p>这也可以用于对现有表单进行修改，例如通过指定要用于特定字段的小部件：</p>\n<div class=\"code-block\" data-language=\"pycon\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python console</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python console code\"><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"kn\">from</span> <span class=\"nn\">django.forms</span> <span class=\"kn\">import</span> Textarea\n<span class=\"gp\">&gt;&gt;&gt; </span>Form <span class=\"o\">=</span> modelform_factory<span class=\"p\">(</span>Book<span class=\"p\">,</span> form<span class=\"o\">=</span>BookForm<span class=\"p\">,</span> widgets<span class=\"o\">=</span><span class=\"p\">{</span><span class=\"s2\">&quot;title&quot;</span><span class=\"p\">:</span> Textarea<span class=\"p\">()})</span>\n</code></pre></div>\n<p>要包含的字段可以使用 <code class=\"docutils literal notranslate\">fields</code> 和 <code class=\"docutils literal notranslate\">exclude</code> 关键字参数或 <code class=\"docutils literal notranslate\">ModelForm</code> 内部的 <code class=\"docutils literal notranslate\">Meta</code> 类中相应的属性来指定。请参阅 <code class=\"docutils literal notranslate\">ModelForm</code> <a class=\"reference internal\" href=\"#modelforms-selecting-fields\"><span class=\"std std-ref\">选择要使用的字段</span></a> 文档。</p>\n<p>... 或者为特定字段启用本地化：</p>\n<div class=\"code-block\" data-language=\"pycon\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python console</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python console code\"><code><span class=\"gp\">&gt;&gt;&gt; </span>Form <span class=\"o\">=</span> modelform_factory<span class=\"p\">(</span>Author<span class=\"p\">,</span> form<span class=\"o\">=</span>AuthorForm<span class=\"p\">,</span> localized_fields<span class=\"o\">=</span><span class=\"p\">[</span><span class=\"s2\">&quot;birth_date&quot;</span><span class=\"p\">])</span>\n</code></pre></div>\n</section>\n</section>\n<section id=\"model-formsets\">\n<span id=\"id1\"></span><h2>模型表单集<a class=\"heading-anchor\" href=\"#model-formsets\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<dl class=\"py class\">\n<dt class=\"sig sig-object py\" id=\"django.forms.models.BaseModelFormSet\">\n<em class=\"property\"><span class=\"k\">class</span> </em><span class=\"sig-prename descclassname\">models.</span><span class=\"sig-name descname\">BaseModelFormSet</span><a class=\"heading-anchor\" href=\"#django.forms.models.BaseModelFormSet\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd></dd></dl>\n\n<p>与 <a class=\"reference internal\" href=\"/zh-hans/5.0/topics/forms/formsets/\"><span class=\"doc\">常规表单集</span></a> 一样，Django 提供了一些增强的表单集类，以更方便地处理 Django 模型。让我们重用上面提到的 <code class=\"docutils literal notranslate\">Author</code> 模型：</p>\n<div class=\"code-block\" data-language=\"pycon\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python console</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python console code\"><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"kn\">from</span> <span class=\"nn\">django.forms</span> <span class=\"kn\">import</span> modelformset_factory\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"kn\">from</span> <span class=\"nn\">myapp.models</span> <span class=\"kn\">import</span> Author\n<span class=\"gp\">&gt;&gt;&gt; </span>AuthorFormSet <span class=\"o\">=</span> modelformset_factory<span class=\"p\">(</span>Author<span class=\"p\">,</span> fields<span class=\"o\">=</span><span class=\"p\">[</span><span class=\"s2\">&quot;name&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;title&quot;</span><span class=\"p\">])</span>\n</code></pre></div>\n<p>使用 <code class=\"docutils literal notranslate\">fields</code> 限制了表单集只使用给定的字段。或者，你可以采用 &quot;排除&quot; 的方式，指定要排除哪些字段：</p>\n<div class=\"code-block\" data-language=\"pycon\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python console</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python console code\"><code><span class=\"gp\">&gt;&gt;&gt; </span>AuthorFormSet <span class=\"o\">=</span> modelformset_factory<span class=\"p\">(</span>Author<span class=\"p\">,</span> exclude<span class=\"o\">=</span><span class=\"p\">[</span><span class=\"s2\">&quot;birth_date&quot;</span><span class=\"p\">])</span>\n</code></pre></div>\n<p>这将创建一个能够处理与 <code class=\"docutils literal notranslate\">Author</code> 模型相关数据的表单集。它的工作方式与常规表单集一样：</p>\n<div class=\"code-block\" data-language=\"pycon\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python console</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python console code\"><code><span class=\"gp\">&gt;&gt;&gt; </span>formset <span class=\"o\">=</span> AuthorFormSet<span class=\"p\">()</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"nb\">print</span><span class=\"p\">(</span>formset<span class=\"p\">)</span>\n<span class=\"go\">&lt;input type=&quot;hidden&quot; name=&quot;form-TOTAL_FORMS&quot; value=&quot;1&quot; id=&quot;id_form-TOTAL_FORMS&quot;&gt;&lt;input type=&quot;hidden&quot; name=&quot;form-INITIAL_FORMS&quot; value=&quot;0&quot; id=&quot;id_form-INITIAL_FORMS&quot;&gt;&lt;input type=&quot;hidden&quot; name=&quot;form-MIN_NUM_FORMS&quot; value=&quot;0&quot; id=&quot;id_form-MIN_NUM_FORMS&quot;&gt;&lt;input type=&quot;hidden&quot; name=&quot;form-MAX_NUM_FORMS&quot; value=&quot;1000&quot; id=&quot;id_form-MAX_NUM_FORMS&quot;&gt;</span>\n<span class=\"go\">&lt;div&gt;&lt;label for=&quot;id_form-0-name&quot;&gt;Name:&lt;/label&gt;&lt;input id=&quot;id_form-0-name&quot; type=&quot;text&quot; name=&quot;form-0-name&quot; maxlength=&quot;100&quot;&gt;&lt;/div&gt;</span>\n<span class=\"go\">&lt;div&gt;&lt;label for=&quot;id_form-0-title&quot;&gt;Title:&lt;/label&gt;&lt;select name=&quot;form-0-title&quot; id=&quot;id_form-0-title&quot;&gt;</span>\n<span class=\"go\">&lt;option value=&quot;&quot; selected&gt;---------&lt;/option&gt;</span>\n<span class=\"go\">&lt;option value=&quot;MR&quot;&gt;Mr.&lt;/option&gt;</span>\n<span class=\"go\">&lt;option value=&quot;MRS&quot;&gt;Mrs.&lt;/option&gt;</span>\n<span class=\"go\">&lt;option value=&quot;MS&quot;&gt;Ms.&lt;/option&gt;</span>\n<span class=\"go\">&lt;/select&gt;&lt;input type=&quot;hidden&quot; name=&quot;form-0-id&quot; id=&quot;id_form-0-id&quot;&gt;&lt;/div&gt;</span>\n</code></pre></div>\n<aside class=\"admonition admonition-note\" role=\"note\">\n<p class=\"admonition-title\">Note</p>\n<p><a class=\"reference internal\" href=\"/zh-hans/5.0/ref/forms/models/#django.forms.models.modelformset_factory\" title=\"django.forms.models.modelformset_factory\"><code class=\"xref py py-func docutils literal notranslate\">modelformset_factory()</code></a> 使用 <a class=\"reference internal\" href=\"/zh-hans/5.0/ref/forms/formsets/#django.forms.formsets.formset_factory\" title=\"django.forms.formsets.formset_factory\"><code class=\"xref py py-func docutils literal notranslate\">formset_factory()</code></a> 来生成表单集。这意味着模型formset是一个知道如何与指定模型交互的普通formset的扩展。</p>\n</aside>\n<aside class=\"admonition admonition-note\" role=\"note\">\n<p class=\"admonition-title\">Note</p>\n<p>当使用多表继承（ <a class=\"reference internal\" href=\"/zh-hans/5.0/topics/db/models/#multi-table-inheritance\"><span class=\"std std-ref\">multi-table inheritance</span></a> ），通过 formset factory 生成的表单将包含父链接字段（默认是 <code class=\"docutils literal notranslate\">2_ptr</code> ）而不是 <code class=\"docutils literal notranslate\">id</code> 字段。</p>\n</aside>\n<section id=\"changing-the-queryset\">\n<h3>更改查询集<a class=\"heading-anchor\" href=\"#changing-the-queryset\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>默认情况下，当你从一个模型创建一个表单集时，表单集将使用包含模型中所有对象的查询集 (例如，<code class=\"docutils literal notranslate\">Author.objects.all()</code>)。你可以通过使用 <code class=\"docutils literal notranslate\">queryset</code> 参数来覆盖这种行为：</p>\n<div class=\"code-block\" data-language=\"pycon\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python console</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python console code\"><code><span class=\"gp\">&gt;&gt;&gt; </span>formset <span class=\"o\">=</span> AuthorFormSet<span class=\"p\">(</span>queryset<span class=\"o\">=</span>Author<span class=\"o\">.</span>objects<span class=\"o\">.</span>filter<span class=\"p\">(</span>name__startswith<span class=\"o\">=</span><span class=\"s2\">&quot;O&quot;</span><span class=\"p\">))</span>\n</code></pre></div>\n<p>或者，您可以创建一个子类，然后在 <code class=\"docutils literal notranslate\">__init__</code> 中设置 <code class=\"docutils literal notranslate\">self.queryset</code> ：</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"kn\">from</span> <span class=\"nn\">django.forms</span> <span class=\"kn\">import</span> BaseModelFormSet\n<span class=\"kn\">from</span> <span class=\"nn\">myapp.models</span> <span class=\"kn\">import</span> Author\n\n\n<span class=\"k\">class</span> <span class=\"nc\">BaseAuthorFormSet</span><span class=\"p\">(</span>BaseModelFormSet<span class=\"p\">):</span>\n    <span class=\"k\">def</span> <span class=\"fm\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"o\">*</span>args<span class=\"p\">,</span> <span class=\"o\">**</span>kwargs<span class=\"p\">):</span>\n        <span class=\"nb\">super</span><span class=\"p\">()</span><span class=\"o\">.</span><span class=\"fm\">__init__</span><span class=\"p\">(</span><span class=\"o\">*</span>args<span class=\"p\">,</span> <span class=\"o\">**</span>kwargs<span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span>queryset <span class=\"o\">=</span> Author<span class=\"o\">.</span>objects<span class=\"o\">.</span>filter<span class=\"p\">(</span>name__startswith<span class=\"o\">=</span><span class=\"s2\">&quot;O&quot;</span><span class=\"p\">)</span>\n</code></pre></div>\n<p>然后，将你的 <code class=\"docutils literal notranslate\">BaseAuthorFormSet</code> 类传递给工厂函数：</p>\n<div class=\"code-block\" data-language=\"pycon\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python console</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python console code\"><code><span class=\"gp\">&gt;&gt;&gt; </span>AuthorFormSet <span class=\"o\">=</span> modelformset_factory<span class=\"p\">(</span>\n<span class=\"gp\">... </span>    Author<span class=\"p\">,</span> fields<span class=\"o\">=</span><span class=\"p\">[</span><span class=\"s2\">&quot;name&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;title&quot;</span><span class=\"p\">],</span> formset<span class=\"o\">=</span>BaseAuthorFormSet\n<span class=\"gp\">... </span><span class=\"p\">)</span>\n</code></pre></div>\n<p>如果你想返回一个不包含 <em>任何</em> 预先存在的模型实例的表单集，你可以指定一个空的查询集：</p>\n<div class=\"code-block\" data-language=\"pycon\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python console</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python console code\"><code><span class=\"gp\">&gt;&gt;&gt; </span>AuthorFormSet<span class=\"p\">(</span>queryset<span class=\"o\">=</span>Author<span class=\"o\">.</span>objects<span class=\"o\">.</span>none<span class=\"p\">())</span>\n</code></pre></div>\n</section>\n<section id=\"changing-the-form\">\n<h3>更改表单<a class=\"heading-anchor\" href=\"#changing-the-form\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>默认情况下，当您使用 <code class=\"docutils literal notranslate\">modelformset_factory</code> 时，程序会用 <a class=\"reference internal\" href=\"/zh-hans/5.0/ref/forms/models/#django.forms.models.modelform_factory\" title=\"django.forms.models.modelform_factory\"><code class=\"xref py py-func docutils literal notranslate\">modelform_factory()</code></a> 创建一个模型表单。这通常在指定自定义模型表单时很有用。例如，您可以创建一个具有自定义验证的自定义模型表单：</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"k\">class</span> <span class=\"nc\">AuthorForm</span><span class=\"p\">(</span>forms<span class=\"o\">.</span>ModelForm<span class=\"p\">):</span>\n    <span class=\"k\">class</span> <span class=\"nc\">Meta</span><span class=\"p\">:</span>\n        model <span class=\"o\">=</span> Author\n        fields <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"s2\">&quot;name&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;title&quot;</span><span class=\"p\">]</span>\n\n    <span class=\"k\">def</span> <span class=\"nf\">clean_name</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"c1\"># custom validation for the name field</span>\n        <span class=\"o\">...</span>\n</code></pre></div>\n<p>然后，将您的模型表单传递给工厂函数：</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code>AuthorFormSet <span class=\"o\">=</span> modelformset_factory<span class=\"p\">(</span>Author<span class=\"p\">,</span> form<span class=\"o\">=</span>AuthorForm<span class=\"p\">)</span>\n</code></pre></div>\n<p>并不是总需要自定义模型表单。 <code class=\"docutils literal notranslate\">modelformset_factory</code> 函数有几个参数传递给 <code class=\"docutils literal notranslate\">modelform_factory</code> ，如下所述。</p>\n</section>\n<section id=\"specifying-widgets-to-use-in-the-form-with-widgets\">\n<h3>在表单中使用 <code class=\"docutils literal notranslate\">widgets</code> 指定部件。<a class=\"heading-anchor\" href=\"#specifying-widgets-to-use-in-the-form-with-widgets\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>使用 <code class=\"docutils literal notranslate\">widgets</code> 参数，你可以指定一个字典的值，以自定义特定字段的 <code class=\"docutils literal notranslate\">ModelForm</code> 的小部件类。这与 <code class=\"docutils literal notranslate\">ModelForm</code> 内部 <code class=\"docutils literal notranslate\">Meta</code> 类上的 <code class=\"docutils literal notranslate\">widgets</code> 字典的工作方式相同：</p>\n<div class=\"code-block\" data-language=\"pycon\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python console</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python console code\"><code><span class=\"gp\">&gt;&gt;&gt; </span>AuthorFormSet <span class=\"o\">=</span> modelformset_factory<span class=\"p\">(</span>\n<span class=\"gp\">... </span>    Author<span class=\"p\">,</span>\n<span class=\"gp\">... </span>    fields<span class=\"o\">=</span><span class=\"p\">[</span><span class=\"s2\">&quot;name&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;title&quot;</span><span class=\"p\">],</span>\n<span class=\"gp\">... </span>    widgets<span class=\"o\">=</span><span class=\"p\">{</span><span class=\"s2\">&quot;name&quot;</span><span class=\"p\">:</span> Textarea<span class=\"p\">(</span>attrs<span class=\"o\">=</span><span class=\"p\">{</span><span class=\"s2\">&quot;cols&quot;</span><span class=\"p\">:</span> <span class=\"mi\">80</span><span class=\"p\">,</span> <span class=\"s2\">&quot;rows&quot;</span><span class=\"p\">:</span> <span class=\"mi\">20</span><span class=\"p\">})},</span>\n<span class=\"gp\">... </span><span class=\"p\">)</span>\n</code></pre></div>\n</section>\n<section id=\"enabling-localization-for-fields-with-localized-fields\">\n<h3>使用 <code class=\"docutils literal notranslate\">localized_fields</code> 来启用字段本地化<a class=\"heading-anchor\" href=\"#enabling-localization-for-fields-with-localized-fields\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>您可以使用 <code class=\"docutils literal notranslate\">localized_fields</code> 参数为表单中的字段启用本地化。</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"gp\">&gt;&gt;&gt; </span>AuthorFormSet <span class=\"o\">=</span> modelformset_factory<span class=\"p\">(</span>\n<span class=\"gp\">... </span>    Author<span class=\"p\">,</span> fields<span class=\"o\">=</span><span class=\"p\">[</span><span class=\"s1\">&#39;name&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;title&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;birth_date&#39;</span><span class=\"p\">],</span>\n<span class=\"gp\">... </span>    localized_fields<span class=\"o\">=</span><span class=\"p\">[</span><span class=\"s1\">&#39;birth_date&#39;</span><span class=\"p\">])</span>\n</code></pre></div>\n<p>如果 <code class=\"docutils literal notranslate\">localized_fields</code> 设置为特殊值 <code class=\"docutils literal notranslate\">'__all__'</code> ，则所有字段都将被本地化。</p>\n</section>\n<section id=\"id2\">\n<h3>提供初始值<a class=\"heading-anchor\" href=\"#id2\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>与常规表单集(formset)一样，在实例化 <a class=\"reference internal\" href=\"/zh-hans/5.0/ref/forms/models/#django.forms.models.modelformset_factory\" title=\"django.forms.models.modelformset_factory\"><code class=\"xref py py-func docutils literal notranslate\">modelformset_factory()</code></a> 返回的模型表单集类时，可以通过指定初始参数来指定表单集中表单的初始数据。然而，对于模型表单集，初始值只适用于额外的表单，不会附加到已存在的模型实例。如果  <code class=\"docutils literal notranslate\">initial</code> 的长度超过了额外表单的数量，多余的初始值会被忽略。如果带有初始值的额外表单没有通过用户去改变，它们不会被验证或保存。</p>\n</section>\n<section id=\"saving-objects-in-the-formset\">\n<span id=\"id3\"></span><h3>在表单集中保存对象<a class=\"heading-anchor\" href=\"#saving-objects-in-the-formset\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>和 <code class=\"docutils literal notranslate\">ModelForm</code> 一样，你可以将数据保存为模型对象。这是通过表单集的 <code class=\"docutils literal notranslate\">save()</code> 方法来完成的：</p>\n<div class=\"code-block\" data-language=\"pycon\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python console</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python console code\"><code><span class=\"go\"># Create a formset instance with POST data.</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>formset <span class=\"o\">=</span> AuthorFormSet<span class=\"p\">(</span>request<span class=\"o\">.</span>POST<span class=\"p\">)</span>\n\n<span class=\"go\"># Assuming all is valid, save the data.</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>instances <span class=\"o\">=</span> formset<span class=\"o\">.</span>save<span class=\"p\">()</span>\n</code></pre></div>\n<p><code class=\"docutils literal notranslate\">save()</code> 方法返回已经保存到数据库的实例。如果一个给定实例的数据没有在绑定数据中改变，那么实例不会被保存到数据库，也不会包含在返回值里（上述例子中的 <code class=\"docutils literal notranslate\">instances</code> ）。</p>\n<p>当表单中缺少字段时（比如因为它们被排除），这些字段不会被 <code class=\"docutils literal notranslate\">save()</code> 方法设置。在选择使用字段里（ <a class=\"reference internal\" href=\"#selecting-the-fields-to-use\">Selecting the fields to use</a> ），你可以找到有关此限制的更多信息，这也适用于的普通的 <code class=\"docutils literal notranslate\">ModelForms</code> 。</p>\n<p>传递 <code class=\"docutils literal notranslate\">commit=False</code>，返回未保存的模型实例：</p>\n<div class=\"code-block\" data-language=\"pycon\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python console</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python console code\"><code><span class=\"go\"># don&#39;t save to the database</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>instances <span class=\"o\">=</span> formset<span class=\"o\">.</span>save<span class=\"p\">(</span>commit<span class=\"o\">=</span><span class=\"kc\">False</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"k\">for</span> instance <span class=\"ow\">in</span> instances<span class=\"p\">:</span>\n<span class=\"gp\">... </span>    <span class=\"c1\"># do something with instance</span>\n<span class=\"gp\">... </span>    instance<span class=\"o\">.</span>save<span class=\"p\">()</span>\n<span class=\"gp\">...</span>\n</code></pre></div>\n<p>这会你在保存它们到数据库之前，附加数据给实例。如果你的表单集包含 <code class=\"docutils literal notranslate\">ManyToManyField</code> ，你也将需要调用 <code class=\"docutils literal notranslate\">formset.save_m2m()</code> 来确保正确保存了多对多关系。</p>\n<p>在调用 <code class=\"docutils literal notranslate\">save()</code> 之后，你的模型表单集将会有三个包含表单集更改的新属性：</p>\n<dl class=\"py attribute\">\n<dt class=\"sig sig-object py\" id=\"django.forms.models.BaseModelFormSet.changed_objects\">\n<span class=\"sig-prename descclassname\">models.BaseModelFormSet.</span><span class=\"sig-name descname\">changed_objects</span><a class=\"heading-anchor\" href=\"#django.forms.models.BaseModelFormSet.changed_objects\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd></dd></dl>\n\n<dl class=\"py attribute\">\n<dt class=\"sig sig-object py\" id=\"django.forms.models.BaseModelFormSet.deleted_objects\">\n<span class=\"sig-prename descclassname\">models.BaseModelFormSet.</span><span class=\"sig-name descname\">deleted_objects</span><a class=\"heading-anchor\" href=\"#django.forms.models.BaseModelFormSet.deleted_objects\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd></dd></dl>\n\n<dl class=\"py attribute\">\n<dt class=\"sig sig-object py\" id=\"django.forms.models.BaseModelFormSet.new_objects\">\n<span class=\"sig-prename descclassname\">models.BaseModelFormSet.</span><span class=\"sig-name descname\">new_objects</span><a class=\"heading-anchor\" href=\"#django.forms.models.BaseModelFormSet.new_objects\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd></dd></dl>\n\n</section>\n<section id=\"limiting-the-number-of-editable-objects\">\n<span id=\"model-formsets-max-num\"></span><h3>限制可编辑对象的数量<a class=\"heading-anchor\" href=\"#limiting-the-number-of-editable-objects\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>和普通表单集一样，你可以使用 <code class=\"docutils literal notranslate\">max_num</code> 和 <code class=\"docutils literal notranslate\">extra</code> 参数来 <a class=\"reference internal\" href=\"/zh-hans/5.0/ref/forms/models/#django.forms.models.modelformset_factory\" title=\"django.forms.models.modelformset_factory\"><code class=\"xref py py-func docutils literal notranslate\">modelformset_factory()</code></a> 来让 <a class=\"reference internal\" href=\"/zh-hans/5.0/ref/forms/models/#django.forms.models.modelformset_factory\" title=\"django.forms.models.modelformset_factory\"><code class=\"xref py py-func docutils literal notranslate\">modelformset_factory()</code></a> 限制显示的额外表单数量。</p>\n<p><code class=\"docutils literal notranslate\">max_num</code> 不会阻止显示现有对象：</p>\n<div class=\"code-block\" data-language=\"pycon\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python console</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python console code\"><code><span class=\"gp\">&gt;&gt;&gt; </span>Author<span class=\"o\">.</span>objects<span class=\"o\">.</span>order_by<span class=\"p\">(</span><span class=\"s2\">&quot;name&quot;</span><span class=\"p\">)</span>\n<span class=\"go\">&lt;QuerySet [&lt;Author: Charles Baudelaire&gt;, &lt;Author: Paul Verlaine&gt;, &lt;Author: Walt Whitman&gt;]&gt;</span>\n\n<span class=\"gp\">&gt;&gt;&gt; </span>AuthorFormSet <span class=\"o\">=</span> modelformset_factory<span class=\"p\">(</span>Author<span class=\"p\">,</span> fields<span class=\"o\">=</span><span class=\"p\">[</span><span class=\"s2\">&quot;name&quot;</span><span class=\"p\">],</span> max_num<span class=\"o\">=</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>formset <span class=\"o\">=</span> AuthorFormSet<span class=\"p\">(</span>queryset<span class=\"o\">=</span>Author<span class=\"o\">.</span>objects<span class=\"o\">.</span>order_by<span class=\"p\">(</span><span class=\"s2\">&quot;name&quot;</span><span class=\"p\">))</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"p\">[</span>x<span class=\"o\">.</span>name <span class=\"k\">for</span> x <span class=\"ow\">in</span> formset<span class=\"o\">.</span>get_queryset<span class=\"p\">()]</span>\n<span class=\"go\">[&#39;Charles Baudelaire&#39;, &#39;Paul Verlaine&#39;, &#39;Walt Whitman&#39;]</span>\n</code></pre></div>\n<p>此外，<code class=\"docutils literal notranslate\">extra=0</code> 并不会阻止创建新的模型实例，因为你可以通过 JavaScript <a class=\"reference internal\" href=\"/zh-hans/5.0/topics/forms/formsets/#understanding-the-managementform\"><span class=\"std std-ref\">添加额外的表单</span></a> 或发送额外的 POST 数据来实现。请参阅 <a class=\"reference internal\" href=\"#model-formsets-edit-only\"><span class=\"std std-ref\">防止创建新对象</span></a> 以了解如何做到这一点。</p>\n<p>如果 <code class=\"docutils literal notranslate\">max_num</code> 的值大于现有相关对象的数量，那么会添加最多 <code class=\"docutils literal notranslate\">extra</code> 个额外的空白表单到表单集中，只要总表单数不超过 <code class=\"docutils literal notranslate\">max_num</code> 即可：</p>\n<div class=\"code-block\" data-language=\"pycon\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python console</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python console code\"><code><span class=\"gp\">&gt;&gt;&gt; </span>AuthorFormSet <span class=\"o\">=</span> modelformset_factory<span class=\"p\">(</span>Author<span class=\"p\">,</span> fields<span class=\"o\">=</span><span class=\"p\">[</span><span class=\"s2\">&quot;name&quot;</span><span class=\"p\">],</span> max_num<span class=\"o\">=</span><span class=\"mi\">4</span><span class=\"p\">,</span> extra<span class=\"o\">=</span><span class=\"mi\">2</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>formset <span class=\"o\">=</span> AuthorFormSet<span class=\"p\">(</span>queryset<span class=\"o\">=</span>Author<span class=\"o\">.</span>objects<span class=\"o\">.</span>order_by<span class=\"p\">(</span><span class=\"s2\">&quot;name&quot;</span><span class=\"p\">))</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"k\">for</span> form <span class=\"ow\">in</span> formset<span class=\"p\">:</span>\n<span class=\"gp\">... </span>    <span class=\"nb\">print</span><span class=\"p\">(</span>form<span class=\"p\">)</span>\n<span class=\"gp\">...</span>\n<span class=\"go\">&lt;div&gt;&lt;label for=&quot;id_form-0-name&quot;&gt;Name:&lt;/label&gt;&lt;input id=&quot;id_form-0-name&quot; type=&quot;text&quot; name=&quot;form-0-name&quot; value=&quot;Charles Baudelaire&quot; maxlength=&quot;100&quot;&gt;&lt;input type=&quot;hidden&quot; name=&quot;form-0-id&quot; value=&quot;1&quot; id=&quot;id_form-0-id&quot;&gt;&lt;/div&gt;</span>\n<span class=\"go\">&lt;div&gt;&lt;label for=&quot;id_form-1-name&quot;&gt;Name:&lt;/label&gt;&lt;input id=&quot;id_form-1-name&quot; type=&quot;text&quot; name=&quot;form-1-name&quot; value=&quot;Paul Verlaine&quot; maxlength=&quot;100&quot;&gt;&lt;input type=&quot;hidden&quot; name=&quot;form-1-id&quot; value=&quot;3&quot; id=&quot;id_form-1-id&quot;&gt;&lt;/div&gt;</span>\n<span class=\"go\">&lt;div&gt;&lt;label for=&quot;id_form-2-name&quot;&gt;Name:&lt;/label&gt;&lt;input id=&quot;id_form-2-name&quot; type=&quot;text&quot; name=&quot;form-2-name&quot; value=&quot;Walt Whitman&quot; maxlength=&quot;100&quot;&gt;&lt;input type=&quot;hidden&quot; name=&quot;form-2-id&quot; value=&quot;2&quot; id=&quot;id_form-2-id&quot;&gt;&lt;/div&gt;</span>\n<span class=\"go\">&lt;div&gt;&lt;label for=&quot;id_form-3-name&quot;&gt;Name:&lt;/label&gt;&lt;input id=&quot;id_form-3-name&quot; type=&quot;text&quot; name=&quot;form-3-name&quot; maxlength=&quot;100&quot;&gt;&lt;input type=&quot;hidden&quot; name=&quot;form-3-id&quot; id=&quot;id_form-3-id&quot;&gt;&lt;/div&gt;</span>\n</code></pre></div>\n<p><code class=\"docutils literal notranslate\">max_num</code> 的值 <code class=\"docutils literal notranslate\">None</code> (默认值)，它限制最多显示(1000)张表单，其实这相当于没有限制。</p>\n</section>\n<section id=\"preventing-new-objects-creation\">\n<span id=\"model-formsets-edit-only\"></span><h3>防止创建新对象<a class=\"heading-anchor\" href=\"#preventing-new-objects-creation\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>使用 <code class=\"docutils literal notranslate\">edit_only</code> 参数，你可以防止创建任何新对象：</p>\n<div class=\"code-block\" data-language=\"pycon\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python console</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python console code\"><code><span class=\"gp\">&gt;&gt;&gt; </span>AuthorFormSet <span class=\"o\">=</span> modelformset_factory<span class=\"p\">(</span>\n<span class=\"gp\">... </span>    Author<span class=\"p\">,</span>\n<span class=\"gp\">... </span>    fields<span class=\"o\">=</span><span class=\"p\">[</span><span class=\"s2\">&quot;name&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;title&quot;</span><span class=\"p\">],</span>\n<span class=\"gp\">... </span>    edit_only<span class=\"o\">=</span><span class=\"kc\">True</span><span class=\"p\">,</span>\n<span class=\"gp\">... </span><span class=\"p\">)</span>\n</code></pre></div>\n<p>在这里，表单集只会编辑现有的 <code class=\"docutils literal notranslate\">Author</code> 实例。不会创建或编辑其他对象。</p>\n</section>\n<section id=\"using-a-model-formset-in-a-view\">\n<h3>在视图中使用模型表单集<a class=\"heading-anchor\" href=\"#using-a-model-formset-in-a-view\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>模型表单集与表单集非常相似。假设我们想要一个表单集来编辑 <code class=\"docutils literal notranslate\">Author</code> 模型实例：</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"kn\">from</span> <span class=\"nn\">django.forms</span> <span class=\"kn\">import</span> modelformset_factory\n<span class=\"kn\">from</span> <span class=\"nn\">django.shortcuts</span> <span class=\"kn\">import</span> render\n<span class=\"kn\">from</span> <span class=\"nn\">myapp.models</span> <span class=\"kn\">import</span> Author\n\n\n<span class=\"k\">def</span> <span class=\"nf\">manage_authors</span><span class=\"p\">(</span>request<span class=\"p\">):</span>\n    AuthorFormSet <span class=\"o\">=</span> modelformset_factory<span class=\"p\">(</span>Author<span class=\"p\">,</span> fields<span class=\"o\">=</span><span class=\"p\">[</span><span class=\"s2\">&quot;name&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;title&quot;</span><span class=\"p\">])</span>\n    <span class=\"k\">if</span> request<span class=\"o\">.</span>method <span class=\"o\">==</span> <span class=\"s2\">&quot;POST&quot;</span><span class=\"p\">:</span>\n        formset <span class=\"o\">=</span> AuthorFormSet<span class=\"p\">(</span>request<span class=\"o\">.</span>POST<span class=\"p\">,</span> request<span class=\"o\">.</span>FILES<span class=\"p\">)</span>\n        <span class=\"k\">if</span> formset<span class=\"o\">.</span>is_valid<span class=\"p\">():</span>\n            formset<span class=\"o\">.</span>save<span class=\"p\">()</span>\n            <span class=\"c1\"># do something.</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        formset <span class=\"o\">=</span> AuthorFormSet<span class=\"p\">()</span>\n    <span class=\"k\">return</span> render<span class=\"p\">(</span>request<span class=\"p\">,</span> <span class=\"s2\">&quot;manage_authors.html&quot;</span><span class=\"p\">,</span> <span class=\"p\">{</span><span class=\"s2\">&quot;formset&quot;</span><span class=\"p\">:</span> formset<span class=\"p\">})</span>\n</code></pre></div>\n<p>像你看到的那样，模型表单集的视图逻辑与普通的表单集并没有太大的不同。唯一的不同是我们调用 <code class=\"docutils literal notranslate\">formset.save()</code> 来保存数据到数据库里。（这已在上面的 <a class=\"reference internal\" href=\"#saving-objects-in-the-formset\"><span class=\"std std-ref\">在表单集中保存对象</span></a> 中描述。）</p>\n</section>\n<section id=\"overriding-clean-on-a-modelformset\">\n<span id=\"model-formsets-overriding-clean\"></span><h3>覆盖 <code class=\"docutils literal notranslate\">ModelFormSet</code> 上的 <code class=\"docutils literal notranslate\">clean()</code><a class=\"heading-anchor\" href=\"#overriding-clean-on-a-modelformset\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>就像 <code class=\"docutils literal notranslate\">ModelForms</code> 一样，默认情况下，<code class=\"docutils literal notranslate\">ModelFormSet</code> 的 <code class=\"docutils literal notranslate\">clean()</code> 方法将验证表单集中没有任何项目违反模型的唯一约束（ <code class=\"docutils literal notranslate\">unique</code>, <code class=\"docutils literal notranslate\">unique_together</code> 或 <code class=\"docutils literal notranslate\">unique_for_date|month|year</code> ）。如果你想覆盖 <code class=\"docutils literal notranslate\">ModelFormSet</code> 上的 <code class=\"docutils literal notranslate\">clean()</code> 方法并保持这个验证，那么你必须调用父类的 <code class=\"docutils literal notranslate\">clean</code> 方法：</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"kn\">from</span> <span class=\"nn\">django.forms</span> <span class=\"kn\">import</span> BaseModelFormSet\n\n\n<span class=\"k\">class</span> <span class=\"nc\">MyModelFormSet</span><span class=\"p\">(</span>BaseModelFormSet<span class=\"p\">):</span>\n    <span class=\"k\">def</span> <span class=\"nf\">clean</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"nb\">super</span><span class=\"p\">()</span><span class=\"o\">.</span>clean<span class=\"p\">()</span>\n        <span class=\"c1\"># example custom validation across forms in the formset</span>\n        <span class=\"k\">for</span> form <span class=\"ow\">in</span> <span class=\"bp\">self</span><span class=\"o\">.</span>forms<span class=\"p\">:</span>\n            <span class=\"c1\"># your custom formset validation</span>\n            <span class=\"o\">...</span>\n</code></pre></div>\n<p>还要注意的是，到达此步时，已经为每个表单创建了独立模型实例。在 <code class=\"docutils literal notranslate\">form.cleaned_data</code> 里修改值不足以影响已保存的值。如果你想在 <code class=\"docutils literal notranslate\">ModelFormSet.clean()</code> 中修改值，你必须修改 <code class=\"docutils literal notranslate\">form.instance</code> ：</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"kn\">from</span> <span class=\"nn\">django.forms</span> <span class=\"kn\">import</span> BaseModelFormSet\n\n\n<span class=\"k\">class</span> <span class=\"nc\">MyModelFormSet</span><span class=\"p\">(</span>BaseModelFormSet<span class=\"p\">):</span>\n    <span class=\"k\">def</span> <span class=\"nf\">clean</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"nb\">super</span><span class=\"p\">()</span><span class=\"o\">.</span>clean<span class=\"p\">()</span>\n\n        <span class=\"k\">for</span> form <span class=\"ow\">in</span> <span class=\"bp\">self</span><span class=\"o\">.</span>forms<span class=\"p\">:</span>\n            name <span class=\"o\">=</span> form<span class=\"o\">.</span>cleaned_data<span class=\"p\">[</span><span class=\"s2\">&quot;name&quot;</span><span class=\"p\">]</span><span class=\"o\">.</span>upper<span class=\"p\">()</span>\n            form<span class=\"o\">.</span>cleaned_data<span class=\"p\">[</span><span class=\"s2\">&quot;name&quot;</span><span class=\"p\">]</span> <span class=\"o\">=</span> name\n            <span class=\"c1\"># update the instance value.</span>\n            form<span class=\"o\">.</span>instance<span class=\"o\">.</span>name <span class=\"o\">=</span> name\n</code></pre></div>\n</section>\n<section id=\"using-a-custom-queryset\">\n<h3>使用自定义查询结果集<a class=\"heading-anchor\" href=\"#using-a-custom-queryset\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>如前所述，你可以覆盖模型表单集使用的默认查询集：</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"kn\">from</span> <span class=\"nn\">django.forms</span> <span class=\"kn\">import</span> modelformset_factory\n<span class=\"kn\">from</span> <span class=\"nn\">django.shortcuts</span> <span class=\"kn\">import</span> render\n<span class=\"kn\">from</span> <span class=\"nn\">myapp.models</span> <span class=\"kn\">import</span> Author\n\n\n<span class=\"k\">def</span> <span class=\"nf\">manage_authors</span><span class=\"p\">(</span>request<span class=\"p\">):</span>\n    AuthorFormSet <span class=\"o\">=</span> modelformset_factory<span class=\"p\">(</span>Author<span class=\"p\">,</span> fields<span class=\"o\">=</span><span class=\"p\">[</span><span class=\"s2\">&quot;name&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;title&quot;</span><span class=\"p\">])</span>\n    queryset <span class=\"o\">=</span> Author<span class=\"o\">.</span>objects<span class=\"o\">.</span>filter<span class=\"p\">(</span>name__startswith<span class=\"o\">=</span><span class=\"s2\">&quot;O&quot;</span><span class=\"p\">)</span>\n    <span class=\"k\">if</span> request<span class=\"o\">.</span>method <span class=\"o\">==</span> <span class=\"s2\">&quot;POST&quot;</span><span class=\"p\">:</span>\n        formset <span class=\"o\">=</span> AuthorFormSet<span class=\"p\">(</span>\n            request<span class=\"o\">.</span>POST<span class=\"p\">,</span>\n            request<span class=\"o\">.</span>FILES<span class=\"p\">,</span>\n            queryset<span class=\"o\">=</span>queryset<span class=\"p\">,</span>\n        <span class=\"p\">)</span>\n        <span class=\"k\">if</span> formset<span class=\"o\">.</span>is_valid<span class=\"p\">():</span>\n            formset<span class=\"o\">.</span>save<span class=\"p\">()</span>\n            <span class=\"c1\"># Do something.</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        formset <span class=\"o\">=</span> AuthorFormSet<span class=\"p\">(</span>queryset<span class=\"o\">=</span>queryset<span class=\"p\">)</span>\n    <span class=\"k\">return</span> render<span class=\"p\">(</span>request<span class=\"p\">,</span> <span class=\"s2\">&quot;manage_authors.html&quot;</span><span class=\"p\">,</span> <span class=\"p\">{</span><span class=\"s2\">&quot;formset&quot;</span><span class=\"p\">:</span> formset<span class=\"p\">})</span>\n</code></pre></div>\n<p>注意我们在这个例子里的 <code class=\"docutils literal notranslate\">POST</code> and <code class=\"docutils literal notranslate\">GET</code> 情况下传递了 <code class=\"docutils literal notranslate\">queryset</code> 参数。</p>\n</section>\n<section id=\"using-the-formset-in-the-template\">\n<h3>在模板中使用表单集<a class=\"heading-anchor\" href=\"#using-the-formset-in-the-template\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>有三种办法在 Django 模板中渲染表单集。</p>\n<p>首先，你可以让表单集完成大部分工作：</p>\n<div class=\"code-block\" data-language=\"html+django\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Django template</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Django template code\"><code><span class=\"p\">&lt;</span><span class=\"nt\">form</span> <span class=\"na\">method</span><span class=\"o\">=</span><span class=\"s\">&quot;post&quot;</span><span class=\"p\">&gt;</span>\n    <span class=\"cp\">{{</span> <span class=\"nv\">formset</span> <span class=\"cp\">}}</span>\n<span class=\"p\">&lt;/</span><span class=\"nt\">form</span><span class=\"p\">&gt;</span>\n</code></pre></div>\n<p>其次，你可以手动渲染表单集，但让表单自己处理自己：</p>\n<div class=\"code-block\" data-language=\"html+django\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Django template</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Django template code\"><code><span class=\"p\">&lt;</span><span class=\"nt\">form</span> <span class=\"na\">method</span><span class=\"o\">=</span><span class=\"s\">&quot;post&quot;</span><span class=\"p\">&gt;</span>\n    <span class=\"cp\">{{</span> <span class=\"nv\">formset.management_form</span> <span class=\"cp\">}}</span>\n    <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>\n        <span class=\"cp\">{{</span> <span class=\"nv\">form</span> <span class=\"cp\">}}</span>\n    <span class=\"cp\">{%</span> <span class=\"k\">endfor</span> <span class=\"cp\">%}</span>\n<span class=\"p\">&lt;/</span><span class=\"nt\">form</span><span class=\"p\">&gt;</span>\n</code></pre></div>\n<p>当你手工渲染表单时，确保渲染了如上所述的管理表单。请查看文档的“管理”部分 （<a class=\"reference internal\" href=\"/zh-hans/5.0/topics/forms/formsets/#understanding-the-managementform\"><span class=\"std std-ref\">management form documentation</span></a> ）</p>\n<p>第三，你可以手动渲染每个字段：</p>\n<div class=\"code-block\" data-language=\"html+django\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Django template</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Django template code\"><code><span class=\"p\">&lt;</span><span class=\"nt\">form</span> <span class=\"na\">method</span><span class=\"o\">=</span><span class=\"s\">&quot;post&quot;</span><span class=\"p\">&gt;</span>\n    <span class=\"cp\">{{</span> <span class=\"nv\">formset.management_form</span> <span class=\"cp\">}}</span>\n    <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>\n        <span class=\"cp\">{%</span> <span class=\"k\">for</span> <span class=\"nv\">field</span> <span class=\"k\">in</span> <span class=\"nv\">form</span> <span class=\"cp\">%}</span>\n            <span class=\"cp\">{{</span> <span class=\"nv\">field.label_tag</span> <span class=\"cp\">}}</span> <span class=\"cp\">{{</span> <span class=\"nv\">field</span> <span class=\"cp\">}}</span>\n        <span class=\"cp\">{%</span> <span class=\"k\">endfor</span> <span class=\"cp\">%}</span>\n    <span class=\"cp\">{%</span> <span class=\"k\">endfor</span> <span class=\"cp\">%}</span>\n<span class=\"p\">&lt;/</span><span class=\"nt\">form</span><span class=\"p\">&gt;</span>\n</code></pre></div>\n<p>如果你选择使用这第三种方法，并且没有使用 <code class=\"docutils literal notranslate\">{% for %}</code> 循环迭代字段，你需要渲染主键字段。例如，如果你要渲染模型的 <code class=\"docutils literal notranslate\">name</code> 和 <code class=\"docutils literal notranslate\">age</code> 字段：</p>\n<div class=\"code-block\" data-language=\"html+django\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Django template</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Django template code\"><code><span class=\"p\">&lt;</span><span class=\"nt\">form</span> <span class=\"na\">method</span><span class=\"o\">=</span><span class=\"s\">&quot;post&quot;</span><span class=\"p\">&gt;</span>\n    <span class=\"cp\">{{</span> <span class=\"nv\">formset.management_form</span> <span class=\"cp\">}}</span>\n    <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>\n        <span class=\"cp\">{{</span> <span class=\"nv\">form.id</span> <span class=\"cp\">}}</span>\n        <span class=\"p\">&lt;</span><span class=\"nt\">ul</span><span class=\"p\">&gt;</span>\n            <span class=\"p\">&lt;</span><span class=\"nt\">li</span><span class=\"p\">&gt;</span><span class=\"cp\">{{</span> <span class=\"nv\">form.name</span> <span class=\"cp\">}}</span><span class=\"p\">&lt;/</span><span class=\"nt\">li</span><span class=\"p\">&gt;</span>\n            <span class=\"p\">&lt;</span><span class=\"nt\">li</span><span class=\"p\">&gt;</span><span class=\"cp\">{{</span> <span class=\"nv\">form.age</span> <span class=\"cp\">}}</span><span class=\"p\">&lt;/</span><span class=\"nt\">li</span><span class=\"p\">&gt;</span>\n        <span class=\"p\">&lt;/</span><span class=\"nt\">ul</span><span class=\"p\">&gt;</span>\n    <span class=\"cp\">{%</span> <span class=\"k\">endfor</span> <span class=\"cp\">%}</span>\n<span class=\"p\">&lt;/</span><span class=\"nt\">form</span><span class=\"p\">&gt;</span>\n</code></pre></div>\n<p>注意我们需要显式地渲染 <code class=\"docutils literal notranslate\">{{ form.id }}</code> 。这将确保在 <code class=\"docutils literal notranslate\">POST</code> 情况下，模型表单集正确工作。（这个例子假设主键名是 <code class=\"docutils literal notranslate\">id</code> 。如果你已经显式定义了不是名为 <code class=\"docutils literal notranslate\">id</code> 的主键，那你需要确保它正确地渲染。）</p>\n</section>\n</section>\n<section id=\"inline-formsets\">\n<span id=\"id4\"></span><h2>内联表单集<a class=\"heading-anchor\" href=\"#inline-formsets\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<dl class=\"py class\">\n<dt class=\"sig sig-object py\" id=\"django.forms.models.BaseInlineFormSet\">\n<em class=\"property\"><span class=\"k\">class</span> </em><span class=\"sig-prename descclassname\">models.</span><span class=\"sig-name descname\">BaseInlineFormSet</span><a class=\"heading-anchor\" href=\"#django.forms.models.BaseInlineFormSet\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd></dd></dl>\n\n<p>内联表单集是在模型表单集上一个很小的抽象层。这些表单集通过外键简化了处理相关对象的情况。假设你有两个模型：</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"kn\">from</span> <span class=\"nn\">django.db</span> <span class=\"kn\">import</span> models\n\n\n<span class=\"k\">class</span> <span class=\"nc\">Author</span><span class=\"p\">(</span>models<span class=\"o\">.</span>Model<span class=\"p\">):</span>\n    name <span class=\"o\">=</span> models<span class=\"o\">.</span>CharField<span class=\"p\">(</span>max_length<span class=\"o\">=</span><span class=\"mi\">100</span><span class=\"p\">)</span>\n\n\n<span class=\"k\">class</span> <span class=\"nc\">Book</span><span class=\"p\">(</span>models<span class=\"o\">.</span>Model<span class=\"p\">):</span>\n    author <span class=\"o\">=</span> models<span class=\"o\">.</span>ForeignKey<span class=\"p\">(</span>Author<span class=\"p\">,</span> on_delete<span class=\"o\">=</span>models<span class=\"o\">.</span>CASCADE<span class=\"p\">)</span>\n    title <span class=\"o\">=</span> models<span class=\"o\">.</span>CharField<span class=\"p\">(</span>max_length<span class=\"o\">=</span><span class=\"mi\">100</span><span class=\"p\">)</span>\n</code></pre></div>\n<p>如果你想创建一个允许你编辑属于特定作者的书籍的表单集，你可以这样做：</p>\n<div class=\"code-block\" data-language=\"pycon\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python console</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python console code\"><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"kn\">from</span> <span class=\"nn\">django.forms</span> <span class=\"kn\">import</span> inlineformset_factory\n<span class=\"gp\">&gt;&gt;&gt; </span>BookFormSet <span class=\"o\">=</span> inlineformset_factory<span class=\"p\">(</span>Author<span class=\"p\">,</span> Book<span class=\"p\">,</span> fields<span class=\"o\">=</span><span class=\"p\">[</span><span class=\"s2\">&quot;title&quot;</span><span class=\"p\">])</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>author <span class=\"o\">=</span> Author<span class=\"o\">.</span>objects<span class=\"o\">.</span>get<span class=\"p\">(</span>name<span class=\"o\">=</span><span class=\"s2\">&quot;Mike Royko&quot;</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>formset <span class=\"o\">=</span> BookFormSet<span class=\"p\">(</span>instance<span class=\"o\">=</span>author<span class=\"p\">)</span>\n</code></pre></div>\n<p><code class=\"docutils literal notranslate\">BookFormSet</code>'s <a class=\"reference internal\" href=\"/zh-hans/5.0/topics/forms/formsets/#formset-prefix\"><span class=\"std std-ref\">prefix</span></a> is <code class=\"docutils literal notranslate\">'book_set'</code> (<code class=\"docutils literal notranslate\">&lt;model name&gt;_set</code> ). 如果 <code class=\"docutils literal notranslate\">Book</code> 的 指向 <code class=\"docutils literal notranslate\">Author</code> 的 <code class=\"docutils literal notranslate\">ForeignKey</code> 有一个 <a class=\"reference internal\" href=\"/zh-hans/5.0/ref/models/fields/#django.db.models.ForeignKey.related_name\" title=\"django.db.models.ForeignKey.related_name\"><code class=\"xref py py-attr docutils literal notranslate\">related_name</code></a> ，则使用它。</p>\n<aside class=\"admonition admonition-note\" role=\"note\">\n<p class=\"admonition-title\">Note</p>\n<p><a class=\"reference internal\" href=\"/zh-hans/5.0/ref/forms/models/#django.forms.models.inlineformset_factory\" title=\"django.forms.models.inlineformset_factory\"><code class=\"xref py py-func docutils literal notranslate\">inlineformset_factory()</code></a> 使用 <a class=\"reference internal\" href=\"/zh-hans/5.0/ref/forms/models/#django.forms.models.modelformset_factory\" title=\"django.forms.models.modelformset_factory\"><code class=\"xref py py-func docutils literal notranslate\">modelformset_factory()</code></a> 并标记 <code class=\"docutils literal notranslate\">can_delete=True</code> 。</p>\n</aside>\n<aside class=\"admonition admonition-seealso\" role=\"note\">\n<p class=\"admonition-title\">See also</p>\n<p>手动渲染 can_delete 和 can_order 。（ <a class=\"reference internal\" href=\"/zh-hans/5.0/topics/forms/formsets/#manually-rendered-can-delete-and-can-order\"><span class=\"std std-ref\">Manually rendered can_delete and can_order</span></a> ）</p>\n</aside>\n<section id=\"overriding-methods-on-an-inlineformset\">\n<h3>覆盖 <code class=\"docutils literal notranslate\">InlineFormSet</code> 上的方法<a class=\"heading-anchor\" href=\"#overriding-methods-on-an-inlineformset\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>当覆盖 <code class=\"docutils literal notranslate\">InlineFormSet</code> 上的方法时，你可以继承 <a class=\"reference internal\" href=\"#django.forms.models.BaseInlineFormSet\" title=\"django.forms.models.BaseInlineFormSet\"><code class=\"xref py py-class docutils literal notranslate\">BaseInlineFormSet</code></a> 而不是 <a class=\"reference internal\" href=\"#django.forms.models.BaseModelFormSet\" title=\"django.forms.models.BaseModelFormSet\"><code class=\"xref py py-class docutils literal notranslate\">BaseModelFormSet</code></a> 。</p>\n<p>比如，如果你想覆盖 <code class=\"docutils literal notranslate\">clean()</code> ：</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"kn\">from</span> <span class=\"nn\">django.forms</span> <span class=\"kn\">import</span> BaseInlineFormSet\n\n\n<span class=\"k\">class</span> <span class=\"nc\">CustomInlineFormSet</span><span class=\"p\">(</span>BaseInlineFormSet<span class=\"p\">):</span>\n    <span class=\"k\">def</span> <span class=\"nf\">clean</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"nb\">super</span><span class=\"p\">()</span><span class=\"o\">.</span>clean<span class=\"p\">()</span>\n        <span class=\"c1\"># example custom validation across forms in the formset</span>\n        <span class=\"k\">for</span> form <span class=\"ow\">in</span> <span class=\"bp\">self</span><span class=\"o\">.</span>forms<span class=\"p\">:</span>\n            <span class=\"c1\"># your custom formset validation</span>\n            <span class=\"o\">...</span>\n</code></pre></div>\n<p>也可以看 <a class=\"reference internal\" href=\"#model-formsets-overriding-clean\"><span class=\"std std-ref\">覆盖 ModelFormSet 上的 clean()</span></a> 。</p>\n<p>然后当你创建内联表单集时，传递可选参数 <code class=\"docutils literal notranslate\">formset</code>：</p>\n<div class=\"code-block\" data-language=\"pycon\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python console</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python console code\"><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"kn\">from</span> <span class=\"nn\">django.forms</span> <span class=\"kn\">import</span> inlineformset_factory\n<span class=\"gp\">&gt;&gt;&gt; </span>BookFormSet <span class=\"o\">=</span> inlineformset_factory<span class=\"p\">(</span>\n<span class=\"gp\">... </span>    Author<span class=\"p\">,</span> Book<span class=\"p\">,</span> fields<span class=\"o\">=</span><span class=\"p\">[</span><span class=\"s2\">&quot;title&quot;</span><span class=\"p\">],</span> formset<span class=\"o\">=</span>CustomInlineFormSet\n<span class=\"gp\">... </span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>author <span class=\"o\">=</span> Author<span class=\"o\">.</span>objects<span class=\"o\">.</span>get<span class=\"p\">(</span>name<span class=\"o\">=</span><span class=\"s2\">&quot;Mike Royko&quot;</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>formset <span class=\"o\">=</span> BookFormSet<span class=\"p\">(</span>instance<span class=\"o\">=</span>author<span class=\"p\">)</span>\n</code></pre></div>\n</section>\n<section id=\"more-than-one-foreign-key-to-the-same-model\">\n<h3>同一个模型有多个外键<a class=\"heading-anchor\" href=\"#more-than-one-foreign-key-to-the-same-model\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>如果你的模型包含多个外键，你需要解决使用 <code class=\"docutils literal notranslate\">fk_name</code> 来解决歧义。比如下面的模型：</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"k\">class</span> <span class=\"nc\">Friendship</span><span class=\"p\">(</span>models<span class=\"o\">.</span>Model<span class=\"p\">):</span>\n    from_friend <span class=\"o\">=</span> models<span class=\"o\">.</span>ForeignKey<span class=\"p\">(</span>\n        Friend<span class=\"p\">,</span>\n        on_delete<span class=\"o\">=</span>models<span class=\"o\">.</span>CASCADE<span class=\"p\">,</span>\n        related_name<span class=\"o\">=</span><span class=\"s2\">&quot;from_friends&quot;</span><span class=\"p\">,</span>\n    <span class=\"p\">)</span>\n    to_friend <span class=\"o\">=</span> models<span class=\"o\">.</span>ForeignKey<span class=\"p\">(</span>\n        Friend<span class=\"p\">,</span>\n        on_delete<span class=\"o\">=</span>models<span class=\"o\">.</span>CASCADE<span class=\"p\">,</span>\n        related_name<span class=\"o\">=</span><span class=\"s2\">&quot;friends&quot;</span><span class=\"p\">,</span>\n    <span class=\"p\">)</span>\n    length_in_months <span class=\"o\">=</span> models<span class=\"o\">.</span>IntegerField<span class=\"p\">()</span>\n</code></pre></div>\n<p>要解决这个问题，你可以使用 <code class=\"docutils literal notranslate\">fk_name</code> 参数传递给 <a class=\"reference internal\" href=\"/zh-hans/5.0/ref/forms/models/#django.forms.models.inlineformset_factory\" title=\"django.forms.models.inlineformset_factory\"><code class=\"xref py py-func docutils literal notranslate\">inlineformset_factory()</code></a>：</p>\n<div class=\"code-block\" data-language=\"pycon\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python console</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python console code\"><code><span class=\"gp\">&gt;&gt;&gt; </span>FriendshipFormSet <span class=\"o\">=</span> inlineformset_factory<span class=\"p\">(</span>\n<span class=\"gp\">... </span>    Friend<span class=\"p\">,</span> Friendship<span class=\"p\">,</span> fk_name<span class=\"o\">=</span><span class=\"s2\">&quot;from_friend&quot;</span><span class=\"p\">,</span> fields<span class=\"o\">=</span><span class=\"p\">[</span><span class=\"s2\">&quot;to_friend&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;length_in_months&quot;</span><span class=\"p\">]</span>\n<span class=\"gp\">... </span><span class=\"p\">)</span>\n</code></pre></div>\n</section>\n<section id=\"using-an-inline-formset-in-a-view\">\n<h3>在视图中使用内联表单集<a class=\"heading-anchor\" href=\"#using-an-inline-formset-in-a-view\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>你可以提供一个视图来允许用户编辑模型的相关对象。这里是相关做法：</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"k\">def</span> <span class=\"nf\">manage_books</span><span class=\"p\">(</span>request<span class=\"p\">,</span> author_id<span class=\"p\">):</span>\n    author <span class=\"o\">=</span> Author<span class=\"o\">.</span>objects<span class=\"o\">.</span>get<span class=\"p\">(</span>pk<span class=\"o\">=</span>author_id<span class=\"p\">)</span>\n    BookInlineFormSet <span class=\"o\">=</span> inlineformset_factory<span class=\"p\">(</span>Author<span class=\"p\">,</span> Book<span class=\"p\">,</span> fields<span class=\"o\">=</span><span class=\"p\">[</span><span class=\"s2\">&quot;title&quot;</span><span class=\"p\">])</span>\n    <span class=\"k\">if</span> request<span class=\"o\">.</span>method <span class=\"o\">==</span> <span class=\"s2\">&quot;POST&quot;</span><span class=\"p\">:</span>\n        formset <span class=\"o\">=</span> BookInlineFormSet<span class=\"p\">(</span>request<span class=\"o\">.</span>POST<span class=\"p\">,</span> request<span class=\"o\">.</span>FILES<span class=\"p\">,</span> instance<span class=\"o\">=</span>author<span class=\"p\">)</span>\n        <span class=\"k\">if</span> formset<span class=\"o\">.</span>is_valid<span class=\"p\">():</span>\n            formset<span class=\"o\">.</span>save<span class=\"p\">()</span>\n            <span class=\"c1\"># Do something. Should generally end with a redirect. For example:</span>\n            <span class=\"k\">return</span> HttpResponseRedirect<span class=\"p\">(</span>author<span class=\"o\">.</span>get_absolute_url<span class=\"p\">())</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        formset <span class=\"o\">=</span> BookInlineFormSet<span class=\"p\">(</span>instance<span class=\"o\">=</span>author<span class=\"p\">)</span>\n    <span class=\"k\">return</span> render<span class=\"p\">(</span>request<span class=\"p\">,</span> <span class=\"s2\">&quot;manage_books.html&quot;</span><span class=\"p\">,</span> <span class=\"p\">{</span><span class=\"s2\">&quot;formset&quot;</span><span class=\"p\">:</span> formset<span class=\"p\">})</span>\n</code></pre></div>\n<p>请注意我们如何将 <code class=\"docutils literal notranslate\">instance</code> 传递给 <code class=\"docutils literal notranslate\">POST</code> 和 <code class=\"docutils literal notranslate\">GET</code> 的。</p>\n</section>\n<section id=\"specifying-widgets-to-use-in-the-inline-form\">\n<h3>指定要在内联表单中使用的 widgets<a class=\"heading-anchor\" href=\"#specifying-widgets-to-use-in-the-inline-form\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p><code class=\"docutils literal notranslate\">inlineformset_factory</code> 使用 <code class=\"docutils literal notranslate\">modelformset_factory</code>，并传递大部分参数给  <code class=\"docutils literal notranslate\">modelformset_factory</code> 。这意味着你可以使用 <code class=\"docutils literal notranslate\">widgets</code> 参数，就像将它传递给 <code class=\"docutils literal notranslate\">modelformset_factory</code> 一样。请查看 <a class=\"reference internal\" href=\"#specifying-widgets-to-use-in-the-form-with-widgets\">Specifying widgets to use in the form with widgets</a> 。</p>\n</section>\n</section>","rootId":"creating-forms-from-models","toc":[{"title":"ModelForm","anchor":"modelform","children":[{"title":"字段类型","anchor":"field-types","children":[]},{"title":"一个完整的例子","anchor":"a-full-example","children":[]},{"title":"验证 ModelForm","anchor":"validation-on-a-modelform","children":[{"title":"覆盖 clean() 方法","anchor":"overriding-the-clean-method","children":[]},{"title":"与模型验证交互","anchor":"interaction-with-model-validation","children":[]},{"title":"有关模型的 error_messages 的注意事项","anchor":"considerations-regarding-model-s-error-messages","children":[]}]},{"title":"save() 方法","anchor":"the-save-method","children":[]},{"title":"选择要使用的字段","anchor":"selecting-the-fields-to-use","children":[]},{"title":"覆盖默认字段","anchor":"overriding-the-default-fields","children":[]},{"title":"启用对字段的本地化","anchor":"enabling-localization-of-fields","children":[]},{"title":"表单继承","anchor":"form-inheritance","children":[]},{"title":"提供初始值","anchor":"providing-initial-values","children":[]},{"title":"ModelForm的工厂函数","anchor":"modelform-factory-function","children":[]}]},{"title":"模型表单集","anchor":"model-formsets","children":[{"title":"更改查询集","anchor":"changing-the-queryset","children":[]},{"title":"更改表单","anchor":"changing-the-form","children":[]},{"title":"在表单中使用 widgets 指定部件。","anchor":"specifying-widgets-to-use-in-the-form-with-widgets","children":[]},{"title":"使用 localized_fields 来启用字段本地化","anchor":"enabling-localization-for-fields-with-localized-fields","children":[]},{"title":"提供初始值","anchor":"id2","children":[]},{"title":"在表单集中保存对象","anchor":"saving-objects-in-the-formset","children":[]},{"title":"限制可编辑对象的数量","anchor":"limiting-the-number-of-editable-objects","children":[]},{"title":"防止创建新对象","anchor":"preventing-new-objects-creation","children":[]},{"title":"在视图中使用模型表单集","anchor":"using-a-model-formset-in-a-view","children":[]},{"title":"覆盖 ModelFormSet 上的 clean()","anchor":"overriding-clean-on-a-modelformset","children":[]},{"title":"使用自定义查询结果集","anchor":"using-a-custom-queryset","children":[]},{"title":"在模板中使用表单集","anchor":"using-the-formset-in-the-template","children":[]}]},{"title":"内联表单集","anchor":"inline-formsets","children":[{"title":"覆盖 InlineFormSet 上的方法","anchor":"overriding-methods-on-an-inlineformset","children":[]},{"title":"同一个模型有多个外键","anchor":"more-than-one-foreign-key-to-the-same-model","children":[]},{"title":"在视图中使用内联表单集","anchor":"using-an-inline-formset-in-a-view","children":[]},{"title":"指定要在内联表单中使用的 widgets","anchor":"specifying-widgets-to-use-in-the-inline-form","children":[]}]}],"breadcrumbs":[{"docname":"topics/index","title":"使用 Django","url":"/zh-hans/5.0/topics/"},{"docname":"topics/forms/index","title":"使用表单","url":"/zh-hans/5.0/topics/forms/"}],"prev":{"docname":"topics/forms/formsets","title":"表单集","url":"/zh-hans/5.0/topics/forms/formsets/"},"next":{"docname":"topics/forms/media","title":"表单资源（ Media 类）","url":"/zh-hans/5.0/topics/forms/media/"},"formats":{"html":"/zh-hans/5.0/topics/forms/modelforms/","markdown":"/zh-hans/5.0/topics/forms/modelforms.md","json":"/zh-hans/5.0/topics/forms/modelforms.json"},"source":"https://github.com/django/django/blob/stable/5.0.x/docs/topics/forms/modelforms.txt","official":"https://docs.djangoproject.com/zh-hans/5.0/topics/forms/modelforms/","inVersions":["6.1","6.0","5.2","5.1","5.0","4.2","4.1","4.0","3.2","3.1","3.0","2.2","2.1","2.0"],"inLocales":["en","zh-hans","fr","ja","id","it","pt-br","ko","es","el","pl"]}