{"title":"从模型创建表单","version":"2.0","locale":"zh-hans","docname":"topics/forms/modelforms","url":"/zh-hans/2.0/topics/forms/modelforms/","canonical":"https://djangodocs.dev/zh-hans/2.0/topics/forms/modelforms/","summary":"如果您正在构建一个数据库驱动的应用程序，那么您很有可能会用到与Django模型密切相关的表单。","html":"<span id=\"creating-forms-from-models\"></span><h1>从模型创建表单<a class=\"heading-anchor\" href=\"#module-django.forms.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=\"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> 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=\"s1\">&#39;pub_date&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;headline&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;content&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;reporter&#39;</span><span class=\"p\">]</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/2.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/2.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/2.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/2.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/2.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/2.0/ref/forms/fields/#django.forms.BooleanField\" title=\"django.forms.BooleanField\"><code class=\"xref py py-class docutils literal notranslate\">BooleanField</code></a></p></td>\n</tr>\n<tr class=\"row-even\"><td><p><a class=\"reference internal\" href=\"/zh-hans/2.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/2.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/2.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-odd\"><td><p><a class=\"reference internal\" href=\"/zh-hans/2.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/2.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-even\"><td><p><a class=\"reference internal\" href=\"/zh-hans/2.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/2.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-odd\"><td><p><a class=\"reference internal\" href=\"/zh-hans/2.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/2.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-even\"><td><p><a class=\"reference internal\" href=\"/zh-hans/2.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/2.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/2.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/2.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/2.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/2.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/2.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/2.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/2.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/2.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><code class=\"docutils literal notranslate\">ImageField</code></p></td>\n<td><p><a class=\"reference internal\" href=\"/zh-hans/2.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/2.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/2.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/2.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/2.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/2.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/2.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-even\"><td><p><a class=\"reference internal\" href=\"/zh-hans/2.0/ref/models/fields/#django.db.models.NullBooleanField\" title=\"django.db.models.NullBooleanField\"><code class=\"xref py py-class docutils literal notranslate\">NullBooleanField</code></a></p></td>\n<td><p><a class=\"reference internal\" href=\"/zh-hans/2.0/ref/forms/fields/#django.forms.NullBooleanField\" title=\"django.forms.NullBooleanField\"><code class=\"xref py py-class docutils literal notranslate\">NullBooleanField</code></a></p></td>\n</tr>\n<tr class=\"row-odd\"><td><p><a class=\"reference internal\" href=\"/zh-hans/2.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/2.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/2.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/2.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/2.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/2.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-even\"><td><p><a class=\"reference internal\" href=\"/zh-hans/2.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/2.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/2.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/2.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/2.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/2.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/2.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/2.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</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=\"p\">(</span><span class=\"s1\">&#39;MR&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;Mr.&#39;</span><span class=\"p\">),</span>\n    <span class=\"p\">(</span><span class=\"s1\">&#39;MRS&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;Mrs.&#39;</span><span class=\"p\">),</span>\n    <span class=\"p\">(</span><span class=\"s1\">&#39;MS&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;Ms.&#39;</span><span class=\"p\">),</span>\n<span class=\"p\">)</span>\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<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<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=\"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\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=\"s1\">&#39;name&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;authors&#39;</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<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<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/2.0/ref/forms/validation/\"><span class=\"doc\">验证表单</span></a></p></li>\n<li><p><a class=\"reference internal\" href=\"/zh-hans/2.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/2.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/2.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/2.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>覆盖clean()方法<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/2.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/2.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/2.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/2.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/2.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/2.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/2.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/2.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<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=\"s1\">&#39;unique_together&#39;</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=\"python\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python</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 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/2.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/2.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/2.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/2.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/2.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/2.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=\"python\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python</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 code\"><code><span class=\"c1\"># Create a form instance with POST data.</span>\n<span class=\"o\">&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=\"c1\"># Create, but don&#39;t save the new author instance.</span>\n<span class=\"o\">&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=\"c1\"># Modify the author in some way.</span>\n<span class=\"o\">&gt;&gt;&gt;</span> new_author<span class=\"o\">.</span>some_field <span class=\"o\">=</span> <span class=\"s1\">&#39;some_value&#39;</span>\n\n<span class=\"c1\"># Save the new instance.</span>\n<span class=\"o\">&gt;&gt;&gt;</span> new_author<span class=\"o\">.</span>save<span class=\"p\">()</span>\n\n<span class=\"c1\"># Now, save the many-to-many data for the form.</span>\n<span class=\"o\">&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=\"python\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python</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 code\"><code><span class=\"c1\"># Create a form instance with POST data.</span>\n<span class=\"o\">&gt;&gt;&gt;</span> a <span class=\"o\">=</span> Author<span class=\"p\">()</span>\n<span class=\"o\">&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=\"c1\"># Create and save the new author instance. There&#39;s no need to do anything else.</span>\n<span class=\"o\">&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/2.0/ref/forms/api/#binding-uploaded-files\"><span class=\"std std-ref\">Binding uploaded files to a form</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.com/blog/1068-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<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=\"s1\">&#39;__all__&#39;</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=\"s1\">&#39;title&#39;</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> ， <a href=\"#id1\"><span class=\"problematic\" id=\"id2\">*</span></a>任何*使用 <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=\"s1\">&#39;Mr&#39;</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=\"s1\">&#39;Mr&#39;</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<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=\"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        widgets <span class=\"o\">=</span> <span class=\"p\">{</span>\n            <span class=\"s1\">&#39;name&#39;</span><span class=\"p\">:</span> Textarea<span class=\"p\">(</span>attrs<span class=\"o\">=</span><span class=\"p\">{</span><span class=\"s1\">&#39;cols&#39;</span><span class=\"p\">:</span> <span class=\"mi\">80</span><span class=\"p\">,</span> <span class=\"s1\">&#39;rows&#39;</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> 字典接受组件实例（例如， <code class=\"docutils literal notranslate\">Textarea(...)</code> ）或者类（例如， <code class=\"docutils literal notranslate\">Textarea</code> ）。</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<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=\"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        labels <span class=\"o\">=</span> <span class=\"p\">{</span>\n            <span class=\"s1\">&#39;name&#39;</span><span class=\"p\">:</span> _<span class=\"p\">(</span><span class=\"s1\">&#39;Writer&#39;</span><span class=\"p\">),</span>\n        <span class=\"p\">}</span>\n        help_texts <span class=\"o\">=</span> <span class=\"p\">{</span>\n            <span class=\"s1\">&#39;name&#39;</span><span class=\"p\">:</span> _<span class=\"p\">(</span><span class=\"s1\">&#39;Some useful help text.&#39;</span><span class=\"p\">),</span>\n        <span class=\"p\">}</span>\n        error_messages <span class=\"o\">=</span> <span class=\"p\">{</span>\n            <span class=\"s1\">&#39;name&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span>\n                <span class=\"s1\">&#39;max_length&#39;</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> 来自定义表单实例化的字段类型：</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<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=\"s1\">&#39;pub_date&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;headline&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;content&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;reporter&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;slug&#39;</span><span class=\"p\">]</span>\n        field_classes <span class=\"o\">=</span> <span class=\"p\">{</span>\n            <span class=\"s1\">&#39;slug&#39;</span><span class=\"p\">:</span> MySlugFormField<span class=\"p\">,</span>\n        <span class=\"p\">}</span>\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<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=\"s1\">&#39;pub_date&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;headline&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;content&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;reporter&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;slug&#39;</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=\"s1\">&#39;Use puns liberally&#39;</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=\"s1\">&#39;Use puns liberally&#39;</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=\"s1\">&#39;headline&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;content&#39;</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/2.0/ref/forms/fields/\"><span class=\"doc\">表单字段文档</span></a> 。</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=\"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=\"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>\n<span class=\"gp\">... </span>        <span class=\"o\">...</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.fields</code> 或 <code class=\"docutils literal notranslate\">Meta.exclude</code> 列表，您也可以继承父类的内部 <code class=\"docutils literal notranslate\">Meta</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=\"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=\"s1\">&#39;body&#39;</span><span class=\"p\">,)</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=\"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>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=\"s1\">&#39;headline&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;Initial headline&#39;</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=\"s1\">&#39;headline&#39;</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/2.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=\"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=\"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> 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>\n<span class=\"gp\">... </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=\"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>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/2.0/topics/forms/formsets/\"><span class=\"doc\">普通表单集</span></a> 一样，Django提供了几个增强的formset类，可以很方便地配合Django模型使用。让我们重用下上面的 <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=\"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=\"s1\">&#39;name&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;title&#39;</span><span class=\"p\">))</span>\n</code></pre></div>\n<p>使用 <code class=\"docutils literal notranslate\">fields</code> 参数限制formset仅使用给定的字段。或者，您可以使用排除法，指定排除哪些字段：</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>Author<span class=\"p\">,</span> exclude<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\">Author</code> 模型相关数据的formset。它运行起来就像一个普通的formset：</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>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-MAX_NUM_FORMS&quot; id=&quot;id_form-MAX_NUM_FORMS&quot; /&gt;</span>\n<span class=\"go\">&lt;tr&gt;&lt;th&gt;&lt;label for=&quot;id_form-0-name&quot;&gt;Name:&lt;/label&gt;&lt;/th&gt;&lt;td&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;/td&gt;&lt;/tr&gt;</span>\n<span class=\"go\">&lt;tr&gt;&lt;th&gt;&lt;label for=&quot;id_form-0-title&quot;&gt;Title:&lt;/label&gt;&lt;/th&gt;&lt;td&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;/td&gt;&lt;/tr&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/2.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/2.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<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>默认情况下，当您创建一个模型ormset时，formset将使用一个包含模型中所有对象（例如 <code class=\"docutils literal notranslate\">Author.objects.all()</code> ）的查询集。你可以通过使用 <code class=\"docutils literal notranslate\">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=\"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=\"s1\">&#39;O&#39;</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<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=\"s1\">&#39;O&#39;</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=\"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> formset<span class=\"o\">=</span>BaseAuthorFormSet<span class=\"p\">)</span>\n</code></pre></div>\n<p>如果您想返回一个不包含 <em>任何</em> 已存在模型实例的formset，您可以指定一个空的QuerySet：</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=\"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/2.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=\"s1\">&#39;name&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;title&#39;</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=\"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>\n<span class=\"gp\">... </span>    widgets<span class=\"o\">=</span><span class=\"p\">{</span><span class=\"s1\">&#39;name&#39;</span><span class=\"p\">:</span> Textarea<span class=\"p\">(</span>attrs<span class=\"o\">=</span><span class=\"p\">{</span><span class=\"s1\">&#39;cols&#39;</span><span class=\"p\">:</span> <span class=\"mi\">80</span><span class=\"p\">,</span> <span class=\"s1\">&#39;rows&#39;</span><span class=\"p\">:</span> <span class=\"mi\">20</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>As with regular formsets, it's possible to <a class=\"reference internal\" href=\"/zh-hans/2.0/topics/forms/formsets/#formsets-initial-data\"><span class=\"std std-ref\">specify initial data</span></a> for forms in the formset by specifying an <code class=\"docutils literal notranslate\">initial</code>\nparameter when instantiating the model formset class returned by\n<a class=\"reference internal\" href=\"/zh-hans/2.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>. However, with model\nformsets, the initial values only apply to extra forms, those that aren't\nattached to an existing model instance. If the extra forms with initial data\naren't changed by the user, they won't be validated or saved.</p>\n</section>\n<section id=\"saving-objects-in-the-formset\">\n<span id=\"id3\"></span><h3>Saving objects in the formset<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>As with a <code class=\"docutils literal notranslate\">ModelForm</code>, you can save the data as a model object. This is done\nwith the formset's <code class=\"docutils literal notranslate\">save()</code> method:</p>\n<div class=\"code-block\" data-language=\"python\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python</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 code\"><code><span class=\"c1\"># Create a formset instance with POST data.</span>\n<span class=\"o\">&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=\"c1\"># Assuming all is valid, save the data.</span>\n<span class=\"o\">&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>The <code class=\"docutils literal notranslate\">save()</code> method returns the instances that have been saved to the\ndatabase. If a given instance's data didn't change in the bound data, the\ninstance won't be saved to the database and won't be included in the return\nvalue (<code class=\"docutils literal notranslate\">instances</code>, in the above example).</p>\n<p>When fields are missing from the form (for example because they have been\nexcluded), these fields will not be set by the <code class=\"docutils literal notranslate\">save()</code> method. You can find\nmore information about this restriction, which also holds for regular\n<code class=\"docutils literal notranslate\">ModelForms</code>, in <a class=\"reference internal\" href=\"#selecting-the-fields-to-use\">Selecting the fields to use</a>.</p>\n<p>Pass <code class=\"docutils literal notranslate\">commit=False</code> to return the unsaved model instances:</p>\n<div class=\"code-block\" data-language=\"python\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python</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 code\"><code><span class=\"c1\"># don&#39;t save to the database</span>\n<span class=\"o\">&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=\"o\">&gt;&gt;&gt;</span> <span class=\"k\">for</span> instance <span class=\"ow\">in</span> instances<span class=\"p\">:</span>\n<span class=\"o\">...</span>     <span class=\"c1\"># do something with instance</span>\n<span class=\"o\">...</span>     instance<span class=\"o\">.</span>save<span class=\"p\">()</span>\n</code></pre></div>\n<p>This gives you the ability to attach data to the instances before saving them\nto the database. If your formset contains a <code class=\"docutils literal notranslate\">ManyToManyField</code>, you'll also\nneed to call <code class=\"docutils literal notranslate\">formset.save_m2m()</code> to ensure the many-to-many relationships\nare saved properly.</p>\n<p>After calling <code class=\"docutils literal notranslate\">save()</code>, your model formset will have three new attributes\ncontaining the formset's changes:</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>Limiting the number of editable objects<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>As with regular formsets, you can use the <code class=\"docutils literal notranslate\">max_num</code> and <code class=\"docutils literal notranslate\">extra</code> parameters\nto <a class=\"reference internal\" href=\"/zh-hans/2.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> to limit the number of\nextra forms displayed.</p>\n<p><code class=\"docutils literal notranslate\">max_num</code> does not prevent existing objects from being displayed:</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>Author<span class=\"o\">.</span>objects<span class=\"o\">.</span>order_by<span class=\"p\">(</span><span class=\"s1\">&#39;name&#39;</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=\"s1\">&#39;name&#39;</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=\"s1\">&#39;name&#39;</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>Also, <code class=\"docutils literal notranslate\">extra=0</code> doesn't prevent creation of new model instances as you can\n<a class=\"reference internal\" href=\"/zh-hans/2.0/topics/forms/formsets/#understanding-the-managementform\"><span class=\"std std-ref\">add additional forms with JavaScript</span></a>\nor just send additional POST data. Formsets <a class=\"reference external\" href=\"https://code.djangoproject.com/ticket/26142\">don't yet provide functionality</a> for an &quot;edit only&quot; view that\nprevents creation of new instances.</p>\n<p>If the value of <code class=\"docutils literal notranslate\">max_num</code> is greater than the number of existing related\nobjects, up to <code class=\"docutils literal notranslate\">extra</code> additional blank forms will be added to the formset,\nso long as the total number of forms does not exceed <code class=\"docutils literal notranslate\">max_num</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>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> 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=\"s1\">&#39;name&#39;</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=\"o\">.</span>as_table<span class=\"p\">())</span>\n<span class=\"go\">&lt;tr&gt;&lt;th&gt;&lt;label for=&quot;id_form-0-name&quot;&gt;Name:&lt;/label&gt;&lt;/th&gt;&lt;td&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;/td&gt;&lt;/tr&gt;</span>\n<span class=\"go\">&lt;tr&gt;&lt;th&gt;&lt;label for=&quot;id_form-1-name&quot;&gt;Name:&lt;/label&gt;&lt;/th&gt;&lt;td&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;/td&gt;&lt;/tr&gt;</span>\n<span class=\"go\">&lt;tr&gt;&lt;th&gt;&lt;label for=&quot;id_form-2-name&quot;&gt;Name:&lt;/label&gt;&lt;/th&gt;&lt;td&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;/td&gt;&lt;/tr&gt;</span>\n<span class=\"go\">&lt;tr&gt;&lt;th&gt;&lt;label for=&quot;id_form-3-name&quot;&gt;Name:&lt;/label&gt;&lt;/th&gt;&lt;td&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;/td&gt;&lt;/tr&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=\"using-a-model-formset-in-a-view\">\n<h3>Using a model formset in a view<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>Model formsets are very similar to formsets. Let's say we want to present a\nformset to edit <code class=\"docutils literal notranslate\">Author</code> model instances:</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<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=\"s1\">&#39;name&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;title&#39;</span><span class=\"p\">))</span>\n    <span class=\"k\">if</span> request<span class=\"o\">.</span>method <span class=\"o\">==</span> <span class=\"s1\">&#39;POST&#39;</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=\"s1\">&#39;manage_authors.html&#39;</span><span class=\"p\">,</span> <span class=\"p\">{</span><span class=\"s1\">&#39;formset&#39;</span><span class=\"p\">:</span> formset<span class=\"p\">})</span>\n</code></pre></div>\n<p>As you can see, the view logic of a model formset isn't drastically different\nthan that of a &quot;normal&quot; formset. The only difference is that we call\n<code class=\"docutils literal notranslate\">formset.save()</code> to save the data into the database. (This was described\nabove, in <a class=\"reference internal\" href=\"#saving-objects-in-the-formset\"><span class=\"std std-ref\">Saving objects in the formset</span></a>.)</p>\n</section>\n<section id=\"overriding-clean-on-a-modelformset\">\n<span id=\"model-formsets-overriding-clean\"></span><h3>Overriding <code class=\"docutils literal notranslate\">clean()</code> on a <code class=\"docutils literal notranslate\">ModelFormSet</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>Just like with <code class=\"docutils literal notranslate\">ModelForms</code>, by default the <code class=\"docutils literal notranslate\">clean()</code> method of a\n<code class=\"docutils literal notranslate\">ModelFormSet</code> will validate that none of the items in the formset violate\nthe unique constraints on your model (either <code class=\"docutils literal notranslate\">unique</code>, <code class=\"docutils literal notranslate\">unique_together</code> or\n<code class=\"docutils literal notranslate\">unique_for_date|month|year</code>).  If you want to override the <code class=\"docutils literal notranslate\">clean()</code> method\non a <code class=\"docutils literal notranslate\">ModelFormSet</code> and maintain this validation, you must call the parent\nclass's <code class=\"docutils literal notranslate\">clean</code> method:</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<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>Also note that by the time you reach this step, individual model instances\nhave already been created for each <code class=\"docutils literal notranslate\">Form</code>. Modifying a value in\n<code class=\"docutils literal notranslate\">form.cleaned_data</code> is not sufficient to affect the saved value. If you wish\nto modify a value in <code class=\"docutils literal notranslate\">ModelFormSet.clean()</code> you must modify\n<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<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=\"s1\">&#39;name&#39;</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=\"s1\">&#39;name&#39;</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>Using a custom queryset<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>As stated earlier, you can override the default queryset used by the model\nformset:</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<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=\"s1\">&#39;name&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;title&#39;</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> request<span class=\"o\">.</span>FILES<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=\"s1\">&#39;O&#39;</span><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>Author<span class=\"o\">.</span>objects<span class=\"o\">.</span>filter<span class=\"p\">(</span>name__startswith<span class=\"o\">=</span><span class=\"s1\">&#39;O&#39;</span><span class=\"p\">))</span>\n    <span class=\"k\">return</span> render<span class=\"p\">(</span>request<span class=\"p\">,</span> <span class=\"s1\">&#39;manage_authors.html&#39;</span><span class=\"p\">,</span> <span class=\"p\">{</span><span class=\"s1\">&#39;formset&#39;</span><span class=\"p\">:</span> formset<span class=\"p\">})</span>\n</code></pre></div>\n<p>Note that we pass the <code class=\"docutils literal notranslate\">queryset</code> argument in both the <code class=\"docutils literal notranslate\">POST</code> and <code class=\"docutils literal notranslate\">GET</code>\ncases in this example.</p>\n</section>\n<section id=\"using-the-formset-in-the-template\">\n<h3>Using the formset in the template<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>There are three ways to render a formset in a Django template.</p>\n<p>First, you can let the formset do most of the work:</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>Second, you can manually render the formset, but let the form deal with\nitself:</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>When you manually render the forms yourself, be sure to render the management\nform as shown above. See the <a class=\"reference internal\" href=\"/zh-hans/2.0/topics/forms/formsets/#understanding-the-managementform\"><span class=\"std std-ref\">management form documentation</span></a>.</p>\n<p>Third, you can manually render each field:</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>If you opt to use this third method and you don't iterate over the fields with\na <code class=\"docutils literal notranslate\">{% for %}</code> loop, you'll need to render the primary key field. For example,\nif you were rendering the <code class=\"docutils literal notranslate\">name</code> and <code class=\"docutils literal notranslate\">age</code> fields of a model:</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>Notice how we need to explicitly render <code class=\"docutils literal notranslate\">{{ form.id }}</code>. This ensures that\nthe model formset, in the <code class=\"docutils literal notranslate\">POST</code> case, will work correctly. (This example\nassumes a primary key named <code class=\"docutils literal notranslate\">id</code>. If you've explicitly defined your own\nprimary key that isn't called <code class=\"docutils literal notranslate\">id</code>, make sure it gets rendered.)</p>\n</section>\n</section>\n<section id=\"inline-formsets\">\n<span id=\"id4\"></span><h2>Inline formsets<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>Inline formsets is a small abstraction layer on top of model formsets. These\nsimplify the case of working with related objects via a foreign key. Suppose\nyou have these two models:</p>\n<div class=\"code-block\" data-language=\"python\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python</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 code\"><code><span class=\"kn\">from</span> <span class=\"nn\">django.db</span> <span class=\"kn\">import</span> models\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<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>If you want to create a formset that allows you to edit books belonging to\na particular author, you could do this:</p>\n<div class=\"code-block\" data-language=\"python\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python</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 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=\"s1\">&#39;title&#39;</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=\"s1\">&#39;Mike Royko&#39;</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/2.0/topics/forms/formsets/#formset-prefix\"><span class=\"std std-ref\">prefix</span></a> is <code class=\"docutils literal notranslate\">'book_set'</code>\n(<code class=\"docutils literal notranslate\">&lt;model name&gt;_set</code> ). If <code class=\"docutils literal notranslate\">Book</code>'s <code class=\"docutils literal notranslate\">ForeignKey</code> to <code class=\"docutils literal notranslate\">Author</code> has a\n<a class=\"reference internal\" href=\"/zh-hans/2.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>, that's used instead.</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/2.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> uses\n<a class=\"reference internal\" href=\"/zh-hans/2.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> and marks\n<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><a class=\"reference internal\" href=\"/zh-hans/2.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>Overriding methods on an <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>When overriding methods on <code class=\"docutils literal notranslate\">InlineFormSet</code>, you should subclass\n<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> rather than\n<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>For example, if you want to override <code class=\"docutils literal notranslate\">clean()</code>:</p>\n<div class=\"code-block\" data-language=\"python\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python</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 code\"><code><span class=\"kn\">from</span> <span class=\"nn\">django.forms</span> <span class=\"kn\">import</span> BaseInlineFormSet\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>See also <a class=\"reference internal\" href=\"#model-formsets-overriding-clean\"><span class=\"std std-ref\">Overriding clean() on a ModelFormSet</span></a>.</p>\n<p>Then when you create your inline formset, pass in the optional argument\n<code class=\"docutils literal notranslate\">formset</code>:</p>\n<div class=\"code-block\" data-language=\"python\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python</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 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=\"s1\">&#39;title&#39;</span><span class=\"p\">,),</span>\n<span class=\"gp\">... </span>    formset<span class=\"o\">=</span>CustomInlineFormSet<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=\"s1\">&#39;Mike Royko&#39;</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>More than one foreign key to the same model<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>If your model contains more than one foreign key to the same model, you'll\nneed to resolve the ambiguity manually using <code class=\"docutils literal notranslate\">fk_name</code>. For example, consider\nthe following model:</p>\n<div class=\"code-block\" data-language=\"python\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python</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 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=\"s1\">&#39;from_friends&#39;</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=\"s1\">&#39;friends&#39;</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>To resolve this, you can use <code class=\"docutils literal notranslate\">fk_name</code> to\n<a class=\"reference internal\" href=\"/zh-hans/2.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=\"python\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python</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 code\"><code><span class=\"gp\">&gt;&gt;&gt; </span>FriendshipFormSet <span class=\"o\">=</span> inlineformset_factory<span class=\"p\">(</span>Friend<span class=\"p\">,</span> Friendship<span class=\"p\">,</span> fk_name<span class=\"o\">=</span><span class=\"s1\">&#39;from_friend&#39;</span><span class=\"p\">,</span>\n<span class=\"gp\">... </span>    fields<span class=\"o\">=</span><span class=\"p\">(</span><span class=\"s1\">&#39;to_friend&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;length_in_months&#39;</span><span class=\"p\">))</span>\n</code></pre></div>\n</section>\n<section id=\"using-an-inline-formset-in-a-view\">\n<h3>Using an inline formset in a view<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>You may want to provide a view that allows a user to edit the related objects\nof a model. Here's how you can do that:</p>\n<div class=\"code-block\" data-language=\"python\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python</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 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=\"s1\">&#39;title&#39;</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=\"s1\">&#39;manage_books.html&#39;</span><span class=\"p\">,</span> <span class=\"p\">{</span><span class=\"s1\">&#39;formset&#39;</span><span class=\"p\">:</span> formset<span class=\"p\">})</span>\n</code></pre></div>\n<p>Notice how we pass <code class=\"docutils literal notranslate\">instance</code> in both the <code class=\"docutils literal notranslate\">POST</code> and <code class=\"docutils literal notranslate\">GET</code> cases.</p>\n</section>\n<section id=\"specifying-widgets-to-use-in-the-inline-form\">\n<h3>Specifying widgets to use in the inline form<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> uses <code class=\"docutils literal notranslate\">modelformset_factory</code> and passes most\nof its arguments to <code class=\"docutils literal notranslate\">modelformset_factory</code>. This means you can use\nthe <code class=\"docutils literal notranslate\">widgets</code> parameter in much the same way as passing it to\n<code class=\"docutils literal notranslate\">modelformset_factory</code>. See <a class=\"reference internal\" href=\"#specifying-widgets-to-use-in-the-form-with-widgets\">Specifying widgets to use in the form with\nwidgets</a> above.</p>\n</section>\n</section>","rootId":"module-django.forms.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":"Saving objects in the formset","anchor":"saving-objects-in-the-formset","children":[]},{"title":"Limiting the number of editable objects","anchor":"limiting-the-number-of-editable-objects","children":[]},{"title":"Using a model formset in a view","anchor":"using-a-model-formset-in-a-view","children":[]},{"title":"Overriding clean() on a ModelFormSet","anchor":"overriding-clean-on-a-modelformset","children":[]},{"title":"Using a custom queryset","anchor":"using-a-custom-queryset","children":[]},{"title":"Using the formset in the template","anchor":"using-the-formset-in-the-template","children":[]}]},{"title":"Inline formsets","anchor":"inline-formsets","children":[{"title":"Overriding methods on an InlineFormSet","anchor":"overriding-methods-on-an-inlineformset","children":[]},{"title":"More than one foreign key to the same model","anchor":"more-than-one-foreign-key-to-the-same-model","children":[]},{"title":"Using an inline formset in a view","anchor":"using-an-inline-formset-in-a-view","children":[]},{"title":"Specifying widgets to use in the inline form","anchor":"specifying-widgets-to-use-in-the-inline-form","children":[]}]}],"breadcrumbs":[{"docname":"topics/index","title":"Using Django","url":"/zh-hans/2.0/topics/"},{"docname":"topics/forms/index","title":"使用表单","url":"/zh-hans/2.0/topics/forms/"}],"prev":{"docname":"topics/forms/formsets","title":"表单集","url":"/zh-hans/2.0/topics/forms/formsets/"},"next":{"docname":"topics/forms/media","title":"表单资源（ Media 类）","url":"/zh-hans/2.0/topics/forms/media/"},"formats":{"html":"/zh-hans/2.0/topics/forms/modelforms/","markdown":"/zh-hans/2.0/topics/forms/modelforms.md","json":"/zh-hans/2.0/topics/forms/modelforms.json"},"source":"https://github.com/django/django/blob/stable/2.0.x/docs/topics/forms/modelforms.txt","official":"https://docs.djangoproject.com/zh-hans/2.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","pt-br","ko","es","el","pl"]}