{"title":"表单和字段验证","version":"6.0","locale":"zh-hans","docname":"ref/forms/validation","url":"/zh-hans/6.0/ref/forms/validation/","canonical":"https://djangodocs.dev/zh-hans/6.0/ref/forms/validation/","summary":"表单验证发生在清理数据的时候。如果你想自定义这个过程，有各种地方可以进行更改，每个地方都有不同的目的。在表单处理过程中会运行三种类型的清理方法。这些方法通常在调用表单上的 is_valid() 方法时执行。还有其他一些事情也可以触发清理和验证（访问 errors 属性或直接调用 full_clean() ），但通常不需要。…","html":"<h1>表单和字段验证<a class=\"heading-anchor\" href=\"#form-and-field-validation\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h1>\n<p>表单验证发生在清理数据的时候。如果你想自定义这个过程，有各种地方可以进行更改，每个地方都有不同的目的。在表单处理过程中会运行三种类型的清理方法。这些方法通常在调用表单上的 <code class=\"docutils literal notranslate\"><span class=\"pre\">is_valid()</span></code> 方法时执行。还有其他一些事情也可以触发清理和验证（访问 <code class=\"docutils literal notranslate\"><span class=\"pre\">errors</span></code> 属性或直接调用 <code class=\"docutils literal notranslate\"><span class=\"pre\">full_clean()</span></code>），但通常不需要。</p>\n<p>一般来说，任何清理方法都可以在处理的数据出现问题时引发 <code class=\"docutils literal notranslate\"><span class=\"pre\">ValidationError</span></code>，将相关信息传递给 <code class=\"docutils literal notranslate\"><span class=\"pre\">ValidationError</span></code> 构造函数。 <span class=\"xref std std-ref\">参见下文 &lt;raising-validation-error&gt;`</span> 关于引发 <code class=\"docutils literal notranslate\"><span class=\"pre\">ValidationError</span></code> 的最佳实践。如果没有引发 <code class=\"docutils literal notranslate\"><span class=\"pre\">ValidationError</span></code>，该方法应该将清理后（规范化）的数据作为 Python 对象返回。</p>\n<p>大多数验证可以使用 <a class=\"reference internal\" href=\"#validators\">validators</a> —— 可以重复使用的辅助功能来完成。验证器是函数（或可调用对象），它只接受一个参数，并在无效输入时引发 <code class=\"docutils literal notranslate\"><span class=\"pre\">ValidationError</span></code>。验证器在字段的 <code class=\"docutils literal notranslate\"><span class=\"pre\">to_python</span></code> 和 <code class=\"docutils literal notranslate\"><span class=\"pre\">validate</span></code> 方法被调用后运行。</p>\n<p>表单的验证分为几个步骤，可以自定义或覆盖：</p>\n<ul>\n<li><p><code class=\"docutils literal notranslate\"><span class=\"pre\">Field</span></code> 上的 <code class=\"docutils literal notranslate\"><span class=\"pre\">to_python()</span></code> 方法是每次验证的第一步。它强制将值转换为正确的数据类型，并在不可能的情况下引发 <code class=\"docutils literal notranslate\"><span class=\"pre\">ValidationError</span></code>。该方法接受来自部件的原始值并返回转换后的值。例如，一个 <code class=\"docutils literal notranslate\"><span class=\"pre\">FloatField</span></code> 将把数据变成 Python <code class=\"docutils literal notranslate\"><span class=\"pre\">float</span></code> 或引发 <code class=\"docutils literal notranslate\"><span class=\"pre\">ValidationError</span></code>。</p></li>\n<li><p><code class=\"docutils literal notranslate\"><span class=\"pre\">Field</span></code> 上的 <code class=\"docutils literal notranslate\"><span class=\"pre\">validate()</span></code> 方法处理不适合验证器的特定字段验证。它接受一个被强制为正确数据类型的值，并在任何错误时引发 <code class=\"docutils literal notranslate\"><span class=\"pre\">ValidationError</span></code>。这个方法不会返回任何东西，也不应该改变值。你应该覆盖它来处理你不能或不想放在验证器中的验证逻辑。</p></li>\n<li><p><code class=\"docutils literal notranslate\"><span class=\"pre\">Field</span></code> 上的 <code class=\"docutils literal notranslate\"><span class=\"pre\">run_validators()</span></code> 方法会运行该字段的所有验证器，并将所有错误汇总到一个 <code class=\"docutils literal notranslate\"><span class=\"pre\">ValidationError</span></code>。你不应该需要覆盖这个方法。</p></li>\n<li><p><code class=\"docutils literal notranslate\"><span class=\"pre\">Field</span></code> 子类上的 <code class=\"docutils literal notranslate\"><span class=\"pre\">clean()</span></code> 方法负责以正确的顺序运行 <code class=\"docutils literal notranslate\"><span class=\"pre\">to_python()</span></code>、<code class=\"docutils literal notranslate\"><span class=\"pre\">validate()</span></code> 和 <code class=\"docutils literal notranslate\"><span class=\"pre\">run_validators()</span></code> 并传播它们的错误。如果在任何时候，任何一个方法引发了 <code class=\"docutils literal notranslate\"><span class=\"pre\">ValidationError</span></code>，验证就会停止，并引发该错误。该方法返回干净的数据，然后将其插入到表单的 <code class=\"docutils literal notranslate\"><span class=\"pre\">cleaned_data</span></code> 字典中。</p></li>\n<li><p><code class=\"docutils literal notranslate\"><span class=\"pre\">clean_&lt;fieldname&gt;()</span></code> 方法是在表单子类上调用的——其中 <code class=\"docutils literal notranslate\"><span class=\"pre\">&lt;fieldname&gt;</span></code> 被替换为表单字段属性的名称。这个方法做任何特定属性的清理工作，与字段的类型无关。这个方法不传递任何参数。你需要在 <code class=\"docutils literal notranslate\"><span class=\"pre\">self.cleaned_data</span></code> 中查找字段的值，并且记住，此时它将是一个 Python 对象，而不是在表单中提交的原始字符串（它将在 <code class=\"docutils literal notranslate\"><span class=\"pre\">cleaned_data</span></code> 中，因为上面的一般字段 <code class=\"docutils literal notranslate\"><span class=\"pre\">clean()</span></code> 方法已经清理了一次数据）。</p>\n<p>例如，如果你想验证一个叫 <code class=\"docutils literal notranslate\"><span class=\"pre\">serialnumber</span></code> 的 <code class=\"docutils literal notranslate\"><span class=\"pre\">CharField</span></code> 的内容是唯一的，<code class=\"docutils literal notranslate\"><span class=\"pre\">clean_serialnumber()</span></code> 就可以做这件事。你不需要一个特定的字段（它是一个 <code class=\"docutils literal notranslate\"><span class=\"pre\">CharField</span></code>），但你需要一个特定字段的验证，可能的话，清理／规范数据。</p>\n<p>这个方法的返回值会替换 <code class=\"docutils literal notranslate\"><span class=\"pre\">cleaned_data</span></code> 中的现有值，所以它必须是 <code class=\"docutils literal notranslate\"><span class=\"pre\">cleaned_data</span></code> 中的字段值（即使这个方法没有改变它）或一个新的干净值。</p>\n</li>\n<li><p>表单子类的 <code class=\"docutils literal notranslate\"><span class=\"pre\">clean()</span></code> 方法可以执行需要访问多个表单字段的验证。在这里，你可以放入诸如“如果提供了字段 <code class=\"docutils literal notranslate\"><span class=\"pre\">A</span></code>，字段 <code class=\"docutils literal notranslate\"><span class=\"pre\">B</span></code> 必须包含一个有效的电子邮件地址”这样的检查。如果你愿意，这个方法可以返回一个完全不同的字典，这个字典将被用作 <code class=\"docutils literal notranslate\"><span class=\"pre\">cleaned_data</span></code>。</p>\n<p>因为在调用 <code class=\"docutils literal notranslate\"><span class=\"pre\">clean()</span></code> 时，字段验证方法已经运行，所以你也可以访问表单的 <code class=\"docutils literal notranslate\"><span class=\"pre\">errors</span></code> 属性，它包含了所有清理单个字段时产生的错误。</p>\n<p>Note that any errors raised by your <a class=\"reference internal\" href=\"/zh-hans/6.0/ref/forms/api/#django.forms.Form.clean\" title=\"django.forms.Form.clean\"><code class=\"xref py py-meth docutils literal notranslate\"><span class=\"pre\">Form.clean()</span></code></a> override will not\nbe associated with any field in particular. They go into a special\n&quot;field&quot; (called <code class=\"docutils literal notranslate\"><span class=\"pre\">__all__</span></code>), which you can access via the\n<a class=\"reference internal\" href=\"/zh-hans/6.0/ref/forms/api/#django.forms.Form.non_field_errors\" title=\"django.forms.Form.non_field_errors\"><code class=\"xref py py-meth docutils literal notranslate\"><span class=\"pre\">non_field_errors()</span></code></a> method if you need to. If you\nwant to attach errors to a specific field in the form, you need to call\n<a class=\"reference internal\" href=\"/zh-hans/6.0/ref/forms/api/#django.forms.Form.add_error\" title=\"django.forms.Form.add_error\"><code class=\"xref py py-meth docutils literal notranslate\"><span class=\"pre\">add_error()</span></code></a>.</p>\n<p>还需要注意的是，当覆盖 <code class=\"docutils literal notranslate\"><span class=\"pre\">ModelForm</span></code> 子类的 <code class=\"docutils literal notranslate\"><span class=\"pre\">clean()</span></code> 方法时，有一些特殊的注意事项。（更多信息见 <a class=\"reference internal\" href=\"/zh-hans/6.0/topics/forms/modelforms/#overriding-modelform-clean-method\"><span class=\"std std-ref\">模型表单文档</span></a>）</p>\n</li>\n</ul>\n<p>These methods are run in the order given above, one field at a time. That is,\nfor each field in the form (in the order they are declared in the form\ndefinition), the <code class=\"docutils literal notranslate\"><span class=\"pre\">Field.clean()</span></code> method (or its override) is run, then\n<code class=\"docutils literal notranslate\"><span class=\"pre\">clean_&lt;fieldname&gt;()</span></code>. Finally, once those two methods are run for every\nfield, the <a class=\"reference internal\" href=\"/zh-hans/6.0/ref/forms/api/#django.forms.Form.clean\" title=\"django.forms.Form.clean\"><code class=\"xref py py-meth docutils literal notranslate\"><span class=\"pre\">Form.clean()</span></code></a> method, or its override, is executed whether\nor not the previous methods have raised errors.</p>\n<p>以下是这些方法的例子。</p>\n<p>如上所述，这些方法中的任何一种都可能引起 <code class=\"docutils literal notranslate\"><span class=\"pre\">ValidationError</span></code>。对于任何字段，如果 <code class=\"docutils literal notranslate\"><span class=\"pre\">Field.clean()</span></code> 方法引起 <code class=\"docutils literal notranslate\"><span class=\"pre\">ValidationError</span></code>，则不调用任何特定字段的清理方法。但是，所有其余字段的清理方法仍然会被执行。</p>\n<section id=\"raising-validationerror\">\n<span id=\"raising-validation-error\"></span><h2>引发 <code class=\"docutils literal notranslate\"><span class=\"pre\">ValidationError</span></code><a class=\"heading-anchor\" href=\"#raising-validationerror\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>为了使错误信息灵活且易于覆盖，请考虑以下准则：</p>\n<ul>\n<li><p>为构造函数提供一个描述性错误 <code class=\"docutils literal notranslate\"><span class=\"pre\">code</span></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=\"c1\"># Good</span>\n<span class=\"n\">ValidationError</span><span class=\"p\">(</span><span class=\"n\">_</span><span class=\"p\">(</span><span class=\"s2\">&quot;Invalid value&quot;</span><span class=\"p\">),</span> <span class=\"n\">code</span><span class=\"o\">=</span><span class=\"s2\">&quot;invalid&quot;</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># Bad</span>\n<span class=\"n\">ValidationError</span><span class=\"p\">(</span><span class=\"n\">_</span><span class=\"p\">(</span><span class=\"s2\">&quot;Invalid value&quot;</span><span class=\"p\">))</span>\n</code></pre></div>\n</li>\n<li><p>不要在信息中强行加入变量；使用占位符和构造函数的 <code class=\"docutils literal notranslate\"><span class=\"pre\">params</span></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=\"c1\"># Good</span>\n<span class=\"n\">ValidationError</span><span class=\"p\">(</span>\n    <span class=\"n\">_</span><span class=\"p\">(</span><span class=\"s2\">&quot;Invalid value: </span><span class=\"si\">%(value)s</span><span class=\"s2\">&quot;</span><span class=\"p\">),</span>\n    <span class=\"n\">params</span><span class=\"o\">=</span><span class=\"p\">{</span><span class=\"s2\">&quot;value&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;42&quot;</span><span class=\"p\">},</span>\n<span class=\"p\">)</span>\n\n<span class=\"c1\"># Bad</span>\n<span class=\"n\">ValidationError</span><span class=\"p\">(</span><span class=\"n\">_</span><span class=\"p\">(</span><span class=\"s2\">&quot;Invalid value: </span><span class=\"si\">%s</span><span class=\"s2\">&quot;</span><span class=\"p\">)</span> <span class=\"o\">%</span> <span class=\"n\">value</span><span class=\"p\">)</span>\n</code></pre></div>\n</li>\n<li><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=\"c1\"># Good</span>\n<span class=\"n\">ValidationError</span><span class=\"p\">(</span>\n    <span class=\"n\">_</span><span class=\"p\">(</span><span class=\"s2\">&quot;Invalid value: </span><span class=\"si\">%(value)s</span><span class=\"s2\">&quot;</span><span class=\"p\">),</span>\n    <span class=\"n\">params</span><span class=\"o\">=</span><span class=\"p\">{</span><span class=\"s2\">&quot;value&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;42&quot;</span><span class=\"p\">},</span>\n<span class=\"p\">)</span>\n\n<span class=\"c1\"># Bad</span>\n<span class=\"n\">ValidationError</span><span class=\"p\">(</span>\n    <span class=\"n\">_</span><span class=\"p\">(</span><span class=\"s2\">&quot;Invalid value: </span><span class=\"si\">%s</span><span class=\"s2\">&quot;</span><span class=\"p\">),</span>\n    <span class=\"n\">params</span><span class=\"o\">=</span><span class=\"p\">(</span><span class=\"s2\">&quot;42&quot;</span><span class=\"p\">,),</span>\n<span class=\"p\">)</span>\n</code></pre></div>\n</li>\n<li><p>用 <code class=\"docutils literal notranslate\"><span class=\"pre\">gettext</span></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=\"c1\"># Good</span>\n<span class=\"n\">ValidationError</span><span class=\"p\">(</span><span class=\"n\">_</span><span class=\"p\">(</span><span class=\"s2\">&quot;Invalid value&quot;</span><span class=\"p\">))</span>\n\n<span class=\"c1\"># Bad</span>\n<span class=\"n\">ValidationError</span><span class=\"p\">(</span><span class=\"s2\">&quot;Invalid value&quot;</span><span class=\"p\">)</span>\n</code></pre></div>\n</li>\n</ul>\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\">raise</span> <span class=\"n\">ValidationError</span><span class=\"p\">(</span>\n    <span class=\"n\">_</span><span class=\"p\">(</span><span class=\"s2\">&quot;Invalid value: </span><span class=\"si\">%(value)s</span><span class=\"s2\">&quot;</span><span class=\"p\">),</span>\n    <span class=\"n\">code</span><span class=\"o\">=</span><span class=\"s2\">&quot;invalid&quot;</span><span class=\"p\">,</span>\n    <span class=\"n\">params</span><span class=\"o\">=</span><span class=\"p\">{</span><span class=\"s2\">&quot;value&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;42&quot;</span><span class=\"p\">},</span>\n<span class=\"p\">)</span>\n</code></pre></div>\n<p>如果你写的是可重用的表单、表单字段和模型字段，那么遵循这些准则是特别必要的。</p>\n<p>虽然不建议使用，但如果你处于验证链的末端（即你的表单 <code class=\"docutils literal notranslate\"><span class=\"pre\">clean()</span></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=\"n\">ValidationError</span><span class=\"p\">(</span><span class=\"n\">_</span><span class=\"p\">(</span><span class=\"s2\">&quot;Invalid value: </span><span class=\"si\">%s</span><span class=\"s2\">&quot;</span><span class=\"p\">)</span> <span class=\"o\">%</span> <span class=\"n\">value</span><span class=\"p\">)</span>\n</code></pre></div>\n<p><a class=\"reference internal\" href=\"/zh-hans/6.0/ref/forms/api/#django.forms.Form.errors.as_data\" title=\"django.forms.Form.errors.as_data\"><code class=\"xref py py-meth docutils literal notranslate\"><span class=\"pre\">Form.errors.as_data()</span></code></a> 和 <a class=\"reference internal\" href=\"/zh-hans/6.0/ref/forms/api/#django.forms.Form.errors.as_json\" title=\"django.forms.Form.errors.as_json\"><code class=\"xref py py-meth docutils literal notranslate\"><span class=\"pre\">Form.errors.as_json()</span></code></a> 方法极大地受益于功能齐全的 <code class=\"docutils literal notranslate\"><span class=\"pre\">ValidationError</span></code> （带有 <code class=\"docutils literal notranslate\"><span class=\"pre\">code</span></code> 名称和 <code class=\"docutils literal notranslate\"><span class=\"pre\">params</span></code> 字典）。</p>\n<section id=\"raising-multiple-errors\">\n<h3>引发多个错误<a class=\"heading-anchor\" href=\"#raising-multiple-errors\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>如果在清理方法中检测到多个错误，并希望向表单提交者发出所有错误信号，可以将错误列表传递给 <code class=\"docutils literal notranslate\"><span class=\"pre\">ValidationError</span></code> 构造函数。</p>\n<p>如上所述，建议传递一个带有 <code class=\"docutils literal notranslate\"><span class=\"pre\">code</span></code> 和 <code class=\"docutils literal notranslate\"><span class=\"pre\">params</span></code> 的 <code class=\"docutils literal notranslate\"><span class=\"pre\">ValidationError</span></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=\"c1\"># Good</span>\n<span class=\"k\">raise</span> <span class=\"n\">ValidationError</span><span class=\"p\">(</span>\n    <span class=\"p\">[</span>\n        <span class=\"n\">ValidationError</span><span class=\"p\">(</span><span class=\"n\">_</span><span class=\"p\">(</span><span class=\"s2\">&quot;Error 1&quot;</span><span class=\"p\">),</span> <span class=\"n\">code</span><span class=\"o\">=</span><span class=\"s2\">&quot;error1&quot;</span><span class=\"p\">),</span>\n        <span class=\"n\">ValidationError</span><span class=\"p\">(</span><span class=\"n\">_</span><span class=\"p\">(</span><span class=\"s2\">&quot;Error 2&quot;</span><span class=\"p\">),</span> <span class=\"n\">code</span><span class=\"o\">=</span><span class=\"s2\">&quot;error2&quot;</span><span class=\"p\">),</span>\n    <span class=\"p\">]</span>\n<span class=\"p\">)</span>\n\n<span class=\"c1\"># Bad</span>\n<span class=\"k\">raise</span> <span class=\"n\">ValidationError</span><span class=\"p\">(</span>\n    <span class=\"p\">[</span>\n        <span class=\"n\">_</span><span class=\"p\">(</span><span class=\"s2\">&quot;Error 1&quot;</span><span class=\"p\">),</span>\n        <span class=\"n\">_</span><span class=\"p\">(</span><span class=\"s2\">&quot;Error 2&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=\"using-validation-in-practice\">\n<h2>在实践中使用验证<a class=\"heading-anchor\" href=\"#using-validation-in-practice\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>前面的章节解释了一般表单的验证是如何工作的。由于有时通过看到每个功能的使用，可以更容易地将事情落实到位，这里有一系列使用前面每个功能的小例子。</p>\n<section id=\"using-validators\">\n<span id=\"validators\"></span><h3>使用验证器<a class=\"heading-anchor\" href=\"#using-validators\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>Django 的表单（和模型）字段支持使用被称为验证器的实用函数和类。验证器是一个可调用对象或函数，它接收一个值，如果该值有效则不返回任何内容，如果无效则引发一个 <a class=\"reference internal\" href=\"/zh-hans/6.0/ref/exceptions/#django.core.exceptions.ValidationError\" title=\"django.core.exceptions.ValidationError\"><code class=\"xref py py-exc docutils literal notranslate\"><span class=\"pre\">ValidationError</span></code></a>。这些可以通过字段的 <code class=\"docutils literal notranslate\"><span class=\"pre\">validators</span></code> 参数传递给字段的构造函数，或者在 <a class=\"reference internal\" href=\"/zh-hans/6.0/ref/forms/fields/#django.forms.Field\" title=\"django.forms.Field\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">Field</span></code></a> 类本身的 <code class=\"docutils literal notranslate\"><span class=\"pre\">default_validators</span></code> 属性中定义。</p>\n<p>验证器可以用来验证字段内部的值，我们来看看 Django 的 <code class=\"docutils literal notranslate\"><span class=\"pre\">SlugField</span></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=\"w\"> </span><span class=\"nn\">django.core</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">validators</span>\n<span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.forms</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">CharField</span>\n\n\n<span class=\"k\">class</span><span class=\"w\"> </span><span class=\"nc\">SlugField</span><span class=\"p\">(</span><span class=\"n\">CharField</span><span class=\"p\">):</span>\n    <span class=\"n\">default_validators</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"n\">validators</span><span class=\"o\">.</span><span class=\"n\">validate_slug</span><span class=\"p\">]</span>\n</code></pre></div>\n<p>正如你所看到的，<code class=\"docutils literal notranslate\"><span class=\"pre\">SlugField</span></code> 是一个带有自定义验证器的 <code class=\"docutils literal notranslate\"><span class=\"pre\">CharField</span></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=\"n\">slug</span> <span class=\"o\">=</span> <span class=\"n\">forms</span><span class=\"o\">.</span><span class=\"n\">SlugField</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=\"n\">slug</span> <span class=\"o\">=</span> <span class=\"n\">forms</span><span class=\"o\">.</span><span class=\"n\">CharField</span><span class=\"p\">(</span><span class=\"n\">validators</span><span class=\"o\">=</span><span class=\"p\">[</span><span class=\"n\">validators</span><span class=\"o\">.</span><span class=\"n\">validate_slug</span><span class=\"p\">])</span>\n</code></pre></div>\n<p>常见情况（例如验证电子邮件或正则表达式）可以使用 Django 中现有的验证器类来处理。例如，<code class=\"docutils literal notranslate\"><span class=\"pre\">validators.validate_slug</span></code> 是一个 <a class=\"reference internal\" href=\"/zh-hans/6.0/ref/validators/#django.core.validators.RegexValidator\" title=\"django.core.validators.RegexValidator\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">RegexValidator</span></code></a> 的实例，其第一个参数是模式：<code class=\"docutils literal notranslate\"><span class=\"pre\">^[-a-zA-Z0-9_]+\\Z</span></code>。请参阅 <a class=\"reference internal\" href=\"/zh-hans/6.0/ref/validators/\"><span class=\"doc\">编写验证器</span></a> 部分，查看已有验证器列表以及如何编写验证器的示例。</p>\n</section>\n<section id=\"form-field-default-cleaning\">\n<h3>表单字段默认清理<a class=\"heading-anchor\" href=\"#form-field-default-cleaning\"><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=\"w\"> </span><span class=\"nn\">django</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">forms</span>\n<span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.core.validators</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">validate_email</span>\n\n\n<span class=\"k\">class</span><span class=\"w\"> </span><span class=\"nc\">MultiEmailField</span><span class=\"p\">(</span><span class=\"n\">forms</span><span class=\"o\">.</span><span class=\"n\">Field</span><span class=\"p\">):</span>\n    <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">to_python</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">value</span><span class=\"p\">):</span>\n<span class=\"w\">        </span><span class=\"sd\">&quot;&quot;&quot;Normalize data to a list of strings.&quot;&quot;&quot;</span>\n        <span class=\"c1\"># Return an empty list if no input was given.</span>\n        <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">value</span><span class=\"p\">:</span>\n            <span class=\"k\">return</span> <span class=\"p\">[]</span>\n        <span class=\"k\">return</span> <span class=\"n\">value</span><span class=\"o\">.</span><span class=\"n\">split</span><span class=\"p\">(</span><span class=\"s2\">&quot;,&quot;</span><span class=\"p\">)</span>\n\n    <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">validate</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">value</span><span class=\"p\">):</span>\n<span class=\"w\">        </span><span class=\"sd\">&quot;&quot;&quot;Check if value consists only of valid emails.&quot;&quot;&quot;</span>\n        <span class=\"c1\"># Use the parent&#39;s handling of required fields, etc.</span>\n        <span class=\"nb\">super</span><span class=\"p\">()</span><span class=\"o\">.</span><span class=\"n\">validate</span><span class=\"p\">(</span><span class=\"n\">value</span><span class=\"p\">)</span>\n        <span class=\"k\">for</span> <span class=\"n\">email</span> <span class=\"ow\">in</span> <span class=\"n\">value</span><span class=\"p\">:</span>\n            <span class=\"n\">validate_email</span><span class=\"p\">(</span><span class=\"n\">email</span><span class=\"p\">)</span>\n</code></pre></div>\n<p>每个使用该字段的表单在对字段的数据进行任何操作之前，都会运行这些方法。这是专门针对这种类型的字段进行的清理，不管它随后如何使用。</p>\n<p>让我们创建一个 <code class=\"docutils literal notranslate\"><span class=\"pre\">ContactForm</span></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=\"w\"> </span><span class=\"nc\">ContactForm</span><span class=\"p\">(</span><span class=\"n\">forms</span><span class=\"o\">.</span><span class=\"n\">Form</span><span class=\"p\">):</span>\n    <span class=\"n\">subject</span> <span class=\"o\">=</span> <span class=\"n\">forms</span><span class=\"o\">.</span><span class=\"n\">CharField</span><span class=\"p\">(</span><span class=\"n\">max_length</span><span class=\"o\">=</span><span class=\"mi\">100</span><span class=\"p\">)</span>\n    <span class=\"n\">message</span> <span class=\"o\">=</span> <span class=\"n\">forms</span><span class=\"o\">.</span><span class=\"n\">CharField</span><span class=\"p\">()</span>\n    <span class=\"n\">contact_email</span> <span class=\"o\">=</span> <span class=\"n\">forms</span><span class=\"o\">.</span><span class=\"n\">EmailField</span><span class=\"p\">()</span>\n    <span class=\"n\">recipients</span> <span class=\"o\">=</span> <span class=\"n\">MultiEmailField</span><span class=\"p\">()</span>\n    <span class=\"n\">urgent</span> <span class=\"o\">=</span> <span class=\"n\">forms</span><span class=\"o\">.</span><span class=\"n\">BooleanField</span><span class=\"p\">(</span><span class=\"n\">required</span><span class=\"o\">=</span><span class=\"kc\">False</span><span class=\"p\">)</span>\n</code></pre></div>\n<p>像使用其他表单字段一样使用 <code class=\"docutils literal notranslate\"><span class=\"pre\">MultiEmailField</span></code>。当在表单上调用 <code class=\"docutils literal notranslate\"><span class=\"pre\">is_valid()</span></code> 方法时，<code class=\"docutils literal notranslate\"><span class=\"pre\">MultiEmailField.clean()</span></code> 方法将作为清理过程的一部分被运行，它将反过来调用自定义的 <code class=\"docutils literal notranslate\"><span class=\"pre\">to_python()</span></code> 和 <code class=\"docutils literal notranslate\"><span class=\"pre\">validate()</span></code> 方法。</p>\n</section>\n<section id=\"cleaning-a-specific-field-attribute\">\n<h3>清理一个特定的字段属性<a class=\"heading-anchor\" href=\"#cleaning-a-specific-field-attribute\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>Continuing on from the previous example, suppose that in our <code class=\"docutils literal notranslate\"><span class=\"pre\">ContactForm</span></code>,\nwe want to make sure that the <code class=\"docutils literal notranslate\"><span class=\"pre\">recipients</span></code> field only contains addresses that\nare <code class=\"docutils literal notranslate\"><span class=\"pre\">&#64;example.com</span></code>. This is validation that is specific to our form, so we\ndon't want to put it into the general <code class=\"docutils literal notranslate\"><span class=\"pre\">MultiEmailField</span></code> class. Instead, we\nwrite a cleaning method that operates on the <code class=\"docutils literal notranslate\"><span class=\"pre\">recipients</span></code> field, like so:</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=\"w\"> </span><span class=\"nn\">django</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">forms</span>\n<span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.core.exceptions</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">ValidationError</span>\n\n\n<span class=\"k\">class</span><span class=\"w\"> </span><span class=\"nc\">ContactForm</span><span class=\"p\">(</span><span class=\"n\">forms</span><span class=\"o\">.</span><span class=\"n\">Form</span><span class=\"p\">):</span>\n    <span class=\"c1\"># Everything as before.</span>\n    <span class=\"o\">...</span>\n\n    <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">clean_recipients</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"n\">data</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">cleaned_data</span><span class=\"p\">[</span><span class=\"s2\">&quot;recipients&quot;</span><span class=\"p\">]</span>\n        <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"nb\">all</span><span class=\"p\">(</span><span class=\"n\">email</span><span class=\"o\">.</span><span class=\"n\">endswith</span><span class=\"p\">(</span><span class=\"s2\">&quot;@example.com&quot;</span><span class=\"p\">)</span> <span class=\"k\">for</span> <span class=\"n\">email</span> <span class=\"ow\">in</span> <span class=\"n\">data</span><span class=\"p\">):</span>\n            <span class=\"k\">raise</span> <span class=\"n\">ValidationError</span><span class=\"p\">(</span><span class=\"s2\">&quot;All recipients must be @example.com.&quot;</span><span class=\"p\">)</span>\n\n        <span class=\"c1\"># Always return a value to use as the new cleaned data, even if</span>\n        <span class=\"c1\"># this method didn&#39;t change it.</span>\n        <span class=\"k\">return</span> <span class=\"n\">data</span>\n</code></pre></div>\n</section>\n<section id=\"cleaning-and-validating-fields-that-depend-on-each-other\">\n<span id=\"validating-fields-with-clean\"></span><h3>清理和验证相互依赖的字段<a class=\"heading-anchor\" href=\"#cleaning-and-validating-fields-that-depend-on-each-other\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>Suppose we add another requirement to our contact form: if the <code class=\"docutils literal notranslate\"><span class=\"pre\">urgent</span></code> field\nis <code class=\"docutils literal notranslate\"><span class=\"pre\">True</span></code>, the <code class=\"docutils literal notranslate\"><span class=\"pre\">subject</span></code> must contain <code class=\"docutils literal notranslate\"><span class=\"pre\">&quot;help&quot;</span></code>. We are performing\nvalidation on more than one field at a time, so the form's <a class=\"reference internal\" href=\"/zh-hans/6.0/ref/forms/api/#django.forms.Form.clean\" title=\"django.forms.Form.clean\"><code class=\"xref py py-meth docutils literal notranslate\"><span class=\"pre\">clean()</span></code></a>\nmethod is a good spot to do this. Notice that we are talking about the\n<code class=\"docutils literal notranslate\"><span class=\"pre\">clean()</span></code> method on the form here, whereas earlier we were writing a\n<code class=\"docutils literal notranslate\"><span class=\"pre\">clean()</span></code> method on a field. It's important to keep the field and form\ndifference clear when working out where to validate things. Fields are single\ndata points, forms are a collection of fields.</p>\n<p>当表单的 <code class=\"docutils literal notranslate\"><span class=\"pre\">clean()</span></code> 方法被调用时，所有的单独字段清理方法都会被运行（前面两节），所以 <code class=\"docutils literal notranslate\"><span class=\"pre\">self.cleaned_data</span></code> 将被填充到目前为止存活的任何数据中。所以你还需要记住，要验证的字段可能没有通过最初的单个字段检查。</p>\n<p>有两种方法可以报告这一步的任何错误。最常见的方法可能是在表单顶部显示错误。要创建这样一个错误，你可以从 <code class=\"docutils literal notranslate\"><span class=\"pre\">clean()</span></code> 方法中引发一个 <code class=\"docutils literal notranslate\"><span class=\"pre\">ValidationError</span></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=\"w\"> </span><span class=\"nn\">django</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">forms</span>\n<span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.core.exceptions</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">ValidationError</span>\n\n\n<span class=\"k\">class</span><span class=\"w\"> </span><span class=\"nc\">ContactForm</span><span class=\"p\">(</span><span class=\"n\">forms</span><span class=\"o\">.</span><span class=\"n\">Form</span><span class=\"p\">):</span>\n    <span class=\"c1\"># Everything as before.</span>\n    <span class=\"o\">...</span>\n\n    <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">clean</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"n\">cleaned_data</span> <span class=\"o\">=</span> <span class=\"nb\">super</span><span class=\"p\">()</span><span class=\"o\">.</span><span class=\"n\">clean</span><span class=\"p\">()</span>\n        <span class=\"n\">urgent</span> <span class=\"o\">=</span> <span class=\"n\">cleaned_data</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"s2\">&quot;urgent&quot;</span><span class=\"p\">)</span>\n        <span class=\"n\">subject</span> <span class=\"o\">=</span> <span class=\"n\">cleaned_data</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"s2\">&quot;subject&quot;</span><span class=\"p\">)</span>\n\n        <span class=\"k\">if</span> <span class=\"n\">urgent</span> <span class=\"ow\">and</span> <span class=\"n\">subject</span><span class=\"p\">:</span>\n            <span class=\"c1\"># Only do something if both fields are valid so far.</span>\n            <span class=\"k\">if</span> <span class=\"s2\">&quot;help&quot;</span> <span class=\"ow\">not</span> <span class=\"ow\">in</span> <span class=\"n\">subject</span><span class=\"p\">:</span>\n                <span class=\"k\">raise</span> <span class=\"n\">ValidationError</span><span class=\"p\">(</span>\n                    <span class=\"s2\">&quot;Must put &#39;help&#39; in the subject for urgent requests.&quot;</span>\n                <span class=\"p\">)</span>\n</code></pre></div>\n<p>在这段代码中，如果出现验证错误，表单将在表单顶部显示错误信息（通常），描述问题。这种错误属于非字段错误，在模板中用 <code class=\"docutils literal notranslate\"><span class=\"pre\">{form.non_field_errors</span> <span class=\"pre\">}}</span></code> 显示。</p>\n<p>示例代码中对 <code class=\"docutils literal notranslate\"><span class=\"pre\">super().clean()</span></code> 的调用确保了父类中的任何验证逻辑得到了维护。如果你的表单继承了另一个没有在其 <code class=\"docutils literal notranslate\"><span class=\"pre\">clean()</span></code> 方法中返回 <code class=\"docutils literal notranslate\"><span class=\"pre\">cleaned_data</span></code> 字典的表单（这样做是可选的），那么不要给 <code class=\"docutils literal notranslate\"><span class=\"pre\">super()</span></code> 调用的结果分配 <code class=\"docutils literal notranslate\"><span class=\"pre\">cleaned_data</span></code>，而使用 <code class=\"docutils literal notranslate\"><span class=\"pre\">self.cleaned_data</span></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\">def</span><span class=\"w\"> </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><span class=\"n\">clean</span><span class=\"p\">()</span>\n    <span class=\"n\">urgent</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">cleaned_data</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"s2\">&quot;urgent&quot;</span><span class=\"p\">)</span>\n    <span class=\"o\">...</span>\n</code></pre></div>\n<p>The second approach for reporting validation errors might involve assigning the\nerror message to one of the fields. In this case, let's assign an error message\nto both the &quot;subject&quot; and &quot;urgent&quot; rows in the form display. Be careful when\ndoing this in practice, since it can lead to confusing form output. We're\nshowing what is possible here and leaving it up to you and your designers to\nwork out what works effectively in your particular situation. Our new code\n(replacing the previous sample) looks like this:</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=\"w\"> </span><span class=\"nn\">django</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">forms</span>\n\n\n<span class=\"k\">class</span><span class=\"w\"> </span><span class=\"nc\">ContactForm</span><span class=\"p\">(</span><span class=\"n\">forms</span><span class=\"o\">.</span><span class=\"n\">Form</span><span class=\"p\">):</span>\n    <span class=\"c1\"># Everything as before.</span>\n    <span class=\"o\">...</span>\n\n    <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">clean</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"n\">cleaned_data</span> <span class=\"o\">=</span> <span class=\"nb\">super</span><span class=\"p\">()</span><span class=\"o\">.</span><span class=\"n\">clean</span><span class=\"p\">()</span>\n        <span class=\"n\">urgent</span> <span class=\"o\">=</span> <span class=\"n\">cleaned_data</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"s2\">&quot;urgent&quot;</span><span class=\"p\">)</span>\n        <span class=\"n\">subject</span> <span class=\"o\">=</span> <span class=\"n\">cleaned_data</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"s2\">&quot;subject&quot;</span><span class=\"p\">)</span>\n\n        <span class=\"k\">if</span> <span class=\"n\">urgent</span> <span class=\"ow\">and</span> <span class=\"n\">subject</span> <span class=\"ow\">and</span> <span class=\"s2\">&quot;help&quot;</span> <span class=\"ow\">not</span> <span class=\"ow\">in</span> <span class=\"n\">subject</span><span class=\"p\">:</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">add_error</span><span class=\"p\">(</span>\n                <span class=\"s2\">&quot;subject&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;Must put &#39;help&#39; in the subject for urgent requests.&quot;</span>\n            <span class=\"p\">)</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">add_error</span><span class=\"p\">(</span>\n                <span class=\"s2\">&quot;urgent&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;Must not mark urgent unless &#39;help&#39; is in the subject.&quot;</span>\n            <span class=\"p\">)</span>\n</code></pre></div>\n<p><code class=\"docutils literal notranslate\"><span class=\"pre\">add_error()</span></code> 的第二个参数可以是一个字符串，或者最好是 <code class=\"docutils literal notranslate\"><span class=\"pre\">ValidationError</span></code> 的一个实例。更多细节请参见 <a class=\"reference internal\" href=\"#raising-validation-error\"><span class=\"std std-ref\">引发 ValidationError</span></a>。请注意，<code class=\"docutils literal notranslate\"><span class=\"pre\">add_error()</span></code> 会自动从 <code class=\"docutils literal notranslate\"><span class=\"pre\">cleaned_data</span></code> 中删除该字段。</p>\n</section>\n</section>","rootId":"form-and-field-validation","toc":[{"title":"引发 ValidationError","anchor":"raising-validationerror","children":[{"title":"引发多个错误","anchor":"raising-multiple-errors","children":[]}]},{"title":"在实践中使用验证","anchor":"using-validation-in-practice","children":[{"title":"使用验证器","anchor":"using-validators","children":[]},{"title":"表单字段默认清理","anchor":"form-field-default-cleaning","children":[]},{"title":"清理一个特定的字段属性","anchor":"cleaning-a-specific-field-attribute","children":[]},{"title":"清理和验证相互依赖的字段","anchor":"cleaning-and-validating-fields-that-depend-on-each-other","children":[]}]}],"breadcrumbs":[{"docname":"ref/index","title":"API 参考","url":"/zh-hans/6.0/ref/"},{"docname":"ref/forms/index","title":"表单","url":"/zh-hans/6.0/ref/forms/"}],"prev":{"docname":"ref/forms/widgets","title":"部件","url":"/zh-hans/6.0/ref/forms/widgets/"},"next":{"docname":"ref/logging","title":"日志","url":"/zh-hans/6.0/ref/logging/"},"formats":{"html":"/zh-hans/6.0/ref/forms/validation/","markdown":"/zh-hans/6.0/ref/forms/validation.md","json":"/zh-hans/6.0/ref/forms/validation.json"},"source":"https://github.com/django/django/blob/stable/6.0.x/docs/ref/forms/validation.txt","official":"https://docs.djangoproject.com/zh-hans/6.0/ref/forms/validation/","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","sv","zh-hans","ga","fr","ja","id","it","pt-br","ko","es","el","pl"]}