表单API

关于此文档

本文件涵盖了Django表格API的详细信息。你应该读一下 introduction to working with forms 第一。

绑定和未绑定窗体

A Form 实例是 跳跃 一组数据,或 未绑定的 .

  • 如果是 跳跃 对于一组数据,它能够验证该数据并将表单呈现为HTML格式,数据显示在HTML中。

  • 如果是 未绑定的 ,它无法进行验证(因为没有要验证的数据!),但它仍然可以将空白形式呈现为HTML。

class Form[源代码]

要创建未绑定的 Form 实例,实例化类:

>>> f = ContactForm()

若要将数据绑定到表单,请将数据作为字典作为第一个参数传递给 Form 类构造函数:

>>> data = {
...     "subject": "hello",
...     "message": "Hi there",
...     "sender": "foo@example.com",
...     "cc_myself": True,
... }
>>> f = ContactForm(data)

在本字典中,键是字段名,与您的 Form 类。这些值是您试图验证的数据。这些通常是字符串,但不要求是字符串;您传递的数据类型取决于 Field ,稍后我们将看到。

Form.is_bound

如果需要在运行时区分绑定和未绑定的表单实例,请检查表单的 is_bound 属性:

>>> f = ContactForm()
>>> f.is_bound
False
>>> f = ContactForm({"subject": "hello"})
>>> f.is_bound
True

请注意,传递空词典会创建一个 bound 数据为空的表单:

>>> f = ContactForm({})
>>> f.is_bound
True

如果你有束缚 Form 实例并希望以某种方式更改数据,或者如果希望绑定未绑定的 Form 实例到某些数据,创建另一个 Form 实例。无法更改 Form 实例。曾经一次 Form 实例已经创建,您应该认为它的数据是不可变的,不管它是否有数据。

使用表单验证数据

Form.clean()

实施一 clean() 你的方法 Form 当必须为相互依赖的字段添加自定义验证时。见 清理和验证相互依赖的字段 例如用法。

Form.is_valid()

的主要任务是 Form 对象的目的是验证数据。带着捆绑 Form 实例,则调用 is_valid() 方法来运行验证并返回一个指定数据是否有效的布尔值:

>>> data = {
...     "subject": "hello",
...     "message": "Hi there",
...     "sender": "foo@example.com",
...     "cc_myself": True,
... }
>>> f = ContactForm(data)
>>> f.is_valid()
True

让我们尝试使用一些无效数据。在这种情况下, subject 为空(这是一个错误,因为默认情况下所有字段都是必填的)和 sender 不是有效的电子邮件地址:

>>> data = {
...     "subject": "",
...     "message": "Hi there",
...     "sender": "invalid email address",
...     "cc_myself": True,
... }
>>> f = ContactForm(data)
>>> f.is_valid()
False
Form.errors

访问 errors 属性以获取错误消息词典:

>>> f.errors
{'sender': ['Enter a valid email address.'], 'subject': ['This field is required.']}

在本字典中,键是字段名,值是表示错误消息的字符串列表。错误消息存储在列表中,因为一个字段可以有多个错误消息。

您可以访问 errors 不用调用 is_valid() 第一。表单的数据将在您第一次调用 is_valid() 或访问 errors .

验证例程将只被调用一次,不管您访问了多少次 errors 或调用 is_valid() . 这意味着如果验证有副作用,那么这些副作用只会触发一次。

Form.errors.as_data()

返回A dict 将字段映射到原始字段 ValidationError 实例。

>>> f.errors.as_data()
{'sender': [ValidationError(['Enter a valid email address.'])],
'subject': [ValidationError(['This field is required.'])]}

在需要通过它来识别错误的任何时候都可以使用此方法 code . 这样可以在出现给定错误时重写错误消息或在视图中写入自定义逻辑。它还可以用于以自定义格式(例如XML)序列化错误;例如, as_json() 依赖于 as_data() .

需要的是 as_data() 方法是由于向后兼容性。以前 ValidationError 一旦他们 提供 错误消息已添加到 Form.errors 字典。理想的 Form.errors 本来可以储存的 ValidationError 实例和方法 as_ 前缀可以呈现它们,但它必须以另一种方式执行,以避免破坏期望在中呈现错误消息的代码。 Form.errors .

Form.errors.as_json(escape_html=False)

返回序列化为JSON的错误。

>>> f.errors.as_json()
{"sender": [{"message": "Enter a valid email address.", "code": "invalid"}],
"subject": [{"message": "This field is required.", "code": "required"}]}

默认情况下, as_json() 不会逃脱其输出。如果您使用它来处理像对表单视图的AJax请求(客户端解释响应并将错误插入页面中)这样的事情,则您需要确保在客户端逃避结果,以避免跨站点脚本攻击的可能性。您可以在JavaScript中通过以下方式完成此操作: element.textContent = errorText 或使用jQuery $(el).text(errorText) (而不是它的 .html() 功能)。

如果出于某种原因不想使用客户端转义,也可以设置 escape_html=True 错误消息将被转义,以便您可以直接在HTML中使用它们。

Form.errors.get_json_data(escape_html=False)

将错误作为适合序列化到JSON的字典返回。 Form.errors.as_json() 返回序列化的JSON,而返回序列化前的错误数据。

这个 escape_html 参数的行为如中所述 Form.errors.as_json() .

Form.add_error(field, error)

此方法允许从中向特定字段添加错误 Form.clean() 方法,或者完全从窗体外部;例如从视图。

这个 field 参数是应向其添加错误的字段的名称。如果它的价值是 None 错误将被视为返回的非字段错误 Form.non_field_errors() .

这个 error 参数可以是字符串,或者最好是 ValidationError 。看见 饲养 ValidationError 定义表格错误时的最佳实践。

注意 Form.add_error() 自动从中删除相关字段 cleaned_data .

Form.has_error(field, code=None)

此方法返回一个布尔值,指定字段是否有特定错误 code .如果 codeNone ,它会回来的 True 如果字段包含任何错误。

要检查非字段错误,请使用 NON_FIELD_ERRORS 作为 field 参数。

Form.non_field_errors()

此方法返回错误列表 Form.errors 与特定字段无关。这包括 ValidationError 在…中长大的 Form.clean() 和使用添加的错误 Form.add_error(None, "...") .

未绑定形式的行为

验证没有数据的表单是没有意义的,但需要注意的是,以下是未绑定表单的情况:

>>> f = ContactForm()
>>> f.is_valid()
False
>>> f.errors
{}

初始表单值

Form.initial

使用 initial 在运行时声明窗体字段的初始值。例如,您可能希望填写 username 具有当前会话用户名的字段。

要完成此操作,请使用 initial 参数设置为 Form 。此参数(如果给定)应该是将字段名映射到初始值的字典。只包含要为其指定初始值的字段;没有必要在表单中包含所有字段。例如:

>>> f = ContactForm(initial={"subject": "Hi there!"})

这些值仅对未绑定的表单显示,如果未提供特定值,则不会用作回退值。

If a Field defines initial and you include initial when instantiating the Form, then the latter initial will have precedence. In this example, initial is provided both at the field level and at the form instance level, and the latter gets precedence:

>>> from django import forms
>>> class CommentForm(forms.Form):
...     name = forms.CharField(initial="class")
...     url = forms.URLField()
...     comment = forms.CharField()
...
>>> f = CommentForm(initial={"name": "instance"}, auto_id=False)
>>> print(f)
<div>Name:<input type="text" name="name" value="instance" required></div>
<div>Url:<input type="url" name="url" required></div>
<div>Comment:<input type="text" name="comment" required></div>
Form.get_initial_for_field(field, field_name)

返回表单域的初始数据。它从以下位置检索数据 Form.initial 如果存在,则尝试 Field.initial 。评估可调用值。

建议使用 BoundField.initial 完毕 get_initial_for_field() 因为 BoundField.initial 具有更简单的界面。此外,不同于 get_initial_for_field()BoundField.initial 缓存其值。这在处理返回值可以更改的可计算函数时尤其有用(例如 datetime.nowuuid.uuid4 ):

>>> import uuid
>>> class UUIDCommentForm(CommentForm):
...     identifier = forms.UUIDField(initial=uuid.uuid4)
...
>>> f = UUIDCommentForm()
>>> f.get_initial_for_field(f.fields["identifier"], "identifier")
UUID('972ca9e4-7bfe-4f5b-af7d-07b3aa306334')
>>> f.get_initial_for_field(f.fields["identifier"], "identifier")
UUID('1b411fab-844e-4dec-bd4f-e9b0495f04d0')
>>> # Using BoundField.initial, for comparison
>>> f["identifier"].initial
UUID('28a09c59-5f00-4ed9-9179-a3b074fa9c30')
>>> f["identifier"].initial
UUID('28a09c59-5f00-4ed9-9179-a3b074fa9c30')

检查哪个表单数据已更改

Form.has_changed()

使用 has_changed() 你的方法 Form 当需要检查表单数据是否已从初始数据更改时。

>>> data = {
...     "subject": "hello",
...     "message": "Hi there",
...     "sender": "foo@example.com",
...     "cc_myself": True,
... }
>>> f = ContactForm(data, initial=data)
>>> f.has_changed()
False

提交表格时,我们重新构建表格并提供原始数据,以便进行比较:

>>> f = ContactForm(request.POST, initial=data)
>>> f.has_changed()

has_changed()True 如果数据来自 request.POST 与中提供的不同 initialFalse 否则。结果是通过调用 Field.has_changed() 对于表单中的每个字段。

Form.changed_data

这个 changed_data 属性返回其值在窗体绑定数据(通常为 request.POST )与中提供的不同 initial . 如果没有数据不同,则返回空列表。

>>> f = ContactForm(request.POST, initial=data)
>>> if f.has_changed():
...     print("The following fields changed: %s" % ", ".join(f.changed_data))
...
>>> f.changed_data
['subject', 'message']

从窗体访问字段

Form.fields

您可以访问的字段 Form 实例从ITS fields 属性:

>>> for row in f.fields.values():
...     print(row)
...
<django.forms.fields.CharField object at 0x7ffaac632510>
<django.forms.fields.URLField object at 0x7ffaac632f90>
<django.forms.fields.CharField object at 0x7ffaac3aa050>
>>> f.fields["name"]
<django.forms.fields.CharField object at 0x7ffaac6324d0>

您可以更改该字段并 BoundFieldForm 实例以更改其在表单中的呈现方式:

>>> f.as_div().split("</div>")[0]
'<div><label for="id_subject">Subject:</label><input type="text" name="subject" maxlength="100" required id="id_subject">'
>>> f["subject"].label = "Topic"
>>> f.as_div().split("</div>")[0]
'<div><label for="id_subject">Topic:</label><input type="text" name="subject" maxlength="100" required id="id_subject">'

注意不要更改 base_fields 属性,因为此修改将影响所有后续 ContactForm 同一个Python进程中的实例:

>>> f.base_fields["subject"].label_suffix = "?"
>>> another_f = CommentForm(auto_id=False)
>>> f.as_div().split("</div>")[0]
'<div><label for="id_subject">Subject?</label><input type="text" name="subject" maxlength="100" required id="id_subject">'

访问“干净”数据

Form.cleaned_data

A中的每个字段 Form 类不仅负责验证数据,还负责“清理”数据——将其规范化为一致的格式。这是一个很好的特性,因为它允许以多种方式输入特定字段的数据,从而始终产生一致的输出。

例如, DateField 将输入规范化为python datetime.date 对象。不管是否以格式传递字符串 '1994-07-15' ,A datetime.date 对象或许多其他格式, DateField 总是将其规范化为 datetime.date 对象,只要它有效。

一旦您创建了 Form 实例具有一组数据并对其进行验证,则可以通过其 cleaned_data 属性:

>>> data = {
...     "subject": "hello",
...     "message": "Hi there",
...     "sender": "foo@example.com",
...     "cc_myself": True,
... }
>>> f = ContactForm(data)
>>> f.is_valid()
True
>>> f.cleaned_data
{'cc_myself': True, 'message': 'Hi there', 'sender': 'foo@example.com', 'subject': 'hello'}

注意,任何基于文本的字段——例如 CharFieldEmailField --总是将输入清理为字符串。我们稍后将在本文中介绍编码含义。

如果您的数据有 not 验证、 cleaned_data 字典仅包含有效字段:

>>> data = {
...     "subject": "",
...     "message": "Hi there",
...     "sender": "invalid email address",
...     "cc_myself": True,
... }
>>> f = ContactForm(data)
>>> f.is_valid()
False
>>> f.cleaned_data
{'cc_myself': True, 'message': 'Hi there'}

cleaned_data will always only contain a key for fields defined in the Form, even if you pass extra data when you define the Form. In this example, we pass a bunch of extra fields to the ContactForm constructor, but cleaned_data contains only the form's fields:

>>> data = {
...     "subject": "hello",
...     "message": "Hi there",
...     "sender": "foo@example.com",
...     "cc_myself": True,
...     "extra_field_1": "foo",
...     "extra_field_2": "bar",
...     "extra_field_3": "baz",
... }
>>> f = ContactForm(data)
>>> f.is_valid()
True
>>> f.cleaned_data  # Doesn't contain extra_field_1, etc.
{'cc_myself': True, 'message': 'Hi there', 'sender': 'foo@example.com', 'subject': 'hello'}

Form 是有效的, cleaned_data 将包括的键和值 all 它的字段,即使数据不包括某些可选字段的值。在此示例中,数据字典不包括 nick_name 字段,但是 cleaned_data 包括它,并且值为空值:

>>> from django import forms
>>> class OptionalPersonForm(forms.Form):
...     first_name = forms.CharField()
...     last_name = forms.CharField()
...     nick_name = forms.CharField(required=False)
...
>>> data = {"first_name": "John", "last_name": "Lennon"}
>>> f = OptionalPersonForm(data)
>>> f.is_valid()
True
>>> f.cleaned_data
{'nick_name': '', 'first_name': 'John', 'last_name': 'Lennon'}

在上面的示例中, cleaned_data 价值观 nick_name 设置为空字符串,因为 nick_nameCharFieldCharField s将空值视为空字符串。每个字段类型都知道其“空白”值是什么——例如,对于 DateField 它是 None 而不是空字符串。有关本例中每个字段行为的完整详细信息,请参见“内置”中每个字段的“空值”注释。 Field “类”部分。

您可以编写代码来对特定表单域(基于其名称)或整个表单(考虑各种域的组合)执行验证。有关此的详细信息位于 表单和字段验证 .

将表单输出为HTML

的第二个任务 Form 对象的目的是将其自身呈现为HTML。要做到这一点, print IT:

>>> f = ContactForm()
>>> print(f)
<div><label for="id_subject">Subject:</label><input type="text" name="subject" maxlength="100" required id="id_subject"></div>
<div><label for="id_message">Message:</label><input type="text" name="message" required id="id_message"></div>
<div><label for="id_sender">Sender:</label><input type="email" name="sender" required id="id_sender"></div>
<div><label for="id_cc_myself">Cc myself:</label><input type="checkbox" name="cc_myself" id="id_cc_myself"></div>

如果表单绑定到数据,则HTML输出将相应地包括该数据。例如,如果一个字段由 <input type="text"> ,数据将位于 value 属性。如果一个字段由 <input type="checkbox"> ,则该HTML将包括 checked 如果适用,请执行以下操作:

>>> data = {
...     "subject": "hello",
...     "message": "Hi there",
...     "sender": "foo@example.com",
...     "cc_myself": True,
... }
>>> f = ContactForm(data)
>>> print(f)
<div><label for="id_subject">Subject:</label><input type="text" name="subject" value="hello" maxlength="100" required id="id_subject"></div>
<div><label for="id_message">Message:</label><input type="text" name="message" value="Hi there" required id="id_message"></div>
<div><label for="id_sender">Sender:</label><input type="email" name="sender" value="foo@example.com" required id="id_sender"></div>
<div><label for="id_cc_myself">Cc myself:</label><input type="checkbox" name="cc_myself" id="id_cc_myself" checked></div>

此默认输出会将每个字段换成 <div> 。请注意以下事项:

  • 为了灵活起见,输出会 not 包括 <form></form> 标记或一个 <input type="submit"> 标签。你的工作就是这么做。

  • 每个字段类型都有默认的HTML表示形式。 CharField 由具有 <input type="text">EmailField<input type="email">BooleanField(null=False) 由具有 <input type="checkbox"> .请注意,这些只是合理的默认值;您可以通过使用小部件指定字段使用哪个HTML,我们将很快解释这一点。

  • HTML name 对于每个标记,直接从其在 ContactForm 类。

  • 每个字段的文本标签——例如 'Subject:''Message:''Cc myself:' 通过将所有下划线转换为空格并将第一个字母大写,从字段名生成。同样,请注意,这些只是合理的默认值;您也可以手动指定标签。

  • 每个文本标签都被一个HTML包围 <label> 标记,该标记通过其 id . 它的 id 反过来,是通过提前 'id_' 字段名。这个 id 属性和 <label> 默认情况下,标记包含在输出中,以遵循最佳实践,但您可以更改该行为。

  • 输出使用HTML5语法,目标 <!DOCTYPE html> . 例如,它使用布尔属性,例如 checked 而不是XHTML风格的 checked='checked' .

虽然 <div> 输出是在以下情况下的默认输出样式 print 表单您可以使用自己的表单模板来自定义输出,该模板可以在站点范围内、按表单或按实例进行设置。看见 可重用表单模板

默认渲染

在执行以下操作时的默认渲染 print 表单使用以下方法和属性。

template_name

Form.template_name

将表单转换为字符串时呈现的模板的名称,例如Via print(form) 或在模板中通过 {{ form }}

默认情况下,返回呈现器的 form_template_name 。您可以将其设置为字符串模板名称,以便覆盖特定表单类的名称。

render()

Form.render(template_name=None, context=None, renderer=None)

Render方法由调用 __str__ 以及 Form.as_div()Form.as_table()Form.as_p() ,以及 Form.as_ul() 方法:研究方法。所有参数都是可选的,默认为:

通过路过 template_name 您可以自定义仅用于单个呼叫的模板。

get_context()

Form.get_context()

返回用于呈现表单的模板上下文。

可用的上下文为:

  • form :装订的表格。

  • fields :除隐藏字段外的所有绑定字段。

  • hidden_fields :所有隐藏的绑定字段。

  • errors :所有与字段无关或与隐藏字段相关的表单错误。

template_name_label

Form.template_name_label

用于呈现字段的 <label> ,在调用 BoundField.label_tag()/legend_tag() 。可以通过覆盖此属性或更一般地通过覆盖默认模板来更改每个表单,另请参阅 覆盖内置表单模板

输出样式

更改表单输出样式的建议方法是设置站点范围、每个表单或每个实例的自定义表单模板。看见 可重用表单模板 举个例子。

提供以下帮助器函数是为了实现向后兼容性,它们是 Form.render() 传递一个特定的 template_name 价值。

备注

对于框架提供的模板和输出样式,默认 as_div() 是推荐的 as_p()as_table() ,以及 as_ul() 版本作为模板实现 <fieldset><legend> 对相关输入进行分组,屏幕阅读器用户可以更轻松地导航。

每个帮助器将一个表单方法与一个属性配对,该属性提供适当的模板名称。

as_div()

Form.template_name_div

使用的模板 as_div() 。默认: 'django/forms/div.html'

Form.as_div()

as_div() 将该窗体呈现为一系列 <div> 元素,每个元素 <div> 包含一个字段,例如:

>>> f = ContactForm()
>>> f.as_div()

…提供类似于以下内容的HTML:

<div>
<label for="id_subject">Subject:</label>
<input type="text" name="subject" maxlength="100" required id="id_subject">
</div>
<div>
<label for="id_message">Message:</label>
<input type="text" name="message" required id="id_message">
</div>
<div>
<label for="id_sender">Sender:</label>
<input type="email" name="sender" required id="id_sender">
</div>
<div>
<label for="id_cc_myself">Cc myself:</label>
<input type="checkbox" name="cc_myself" id="id_cc_myself">
</div>

as_p()

Form.template_name_p

使用的模板 as_p() 。默认: 'django/forms/p.html'

Form.as_p()

as_p() 将该窗体呈现为一系列 <p> 标记,每个标记 <p> 包含一个字段:

>>> f = ContactForm()
>>> f.as_p()
'<p><label for="id_subject">Subject:</label> <input id="id_subject" type="text" name="subject" maxlength="100" required></p>\n<p><label for="id_message">Message:</label> <input type="text" name="message" id="id_message" required></p>\n<p><label for="id_sender">Sender:</label> <input type="text" name="sender" id="id_sender" required></p>\n<p><label for="id_cc_myself">Cc myself:</label> <input type="checkbox" name="cc_myself" id="id_cc_myself"></p>'
>>> print(f.as_p())
<p><label for="id_subject">Subject:</label> <input id="id_subject" type="text" name="subject" maxlength="100" required></p>
<p><label for="id_message">Message:</label> <input type="text" name="message" id="id_message" required></p>
<p><label for="id_sender">Sender:</label> <input type="email" name="sender" id="id_sender" required></p>
<p><label for="id_cc_myself">Cc myself:</label> <input type="checkbox" name="cc_myself" id="id_cc_myself"></p>

as_ul()

Form.template_name_ul

使用的模板 as_ul() 。默认: 'django/forms/ul.html'

Form.as_ul()

as_ul() 将该窗体呈现为一系列 <li> 标记,每个标记 <li> 包含一个字段的。是的 not 包括 <ul></ul> ,以便您可以在 <ul> 为提高灵活性:

>>> f = ContactForm()
>>> f.as_ul()
'<li><label for="id_subject">Subject:</label> <input id="id_subject" type="text" name="subject" maxlength="100" required></li>\n<li><label for="id_message">Message:</label> <input type="text" name="message" id="id_message" required></li>\n<li><label for="id_sender">Sender:</label> <input type="email" name="sender" id="id_sender" required></li>\n<li><label for="id_cc_myself">Cc myself:</label> <input type="checkbox" name="cc_myself" id="id_cc_myself"></li>'
>>> print(f.as_ul())
<li><label for="id_subject">Subject:</label> <input id="id_subject" type="text" name="subject" maxlength="100" required></li>
<li><label for="id_message">Message:</label> <input type="text" name="message" id="id_message" required></li>
<li><label for="id_sender">Sender:</label> <input type="email" name="sender" id="id_sender" required></li>
<li><label for="id_cc_myself">Cc myself:</label> <input type="checkbox" name="cc_myself" id="id_cc_myself"></li>

as_table()

Form.template_name_table

使用的模板 as_table() 。默认: 'django/forms/table.html'

Form.as_table()

as_table() 将表单呈现为HTML <table>

>>> f = ContactForm()
>>> f.as_table()
'<tr><th><label for="id_subject">Subject:</label></th><td><input id="id_subject" type="text" name="subject" maxlength="100" required></td></tr>\n<tr><th><label for="id_message">Message:</label></th><td><input type="text" name="message" id="id_message" required></td></tr>\n<tr><th><label for="id_sender">Sender:</label></th><td><input type="email" name="sender" id="id_sender" required></td></tr>\n<tr><th><label for="id_cc_myself">Cc myself:</label></th><td><input type="checkbox" name="cc_myself" id="id_cc_myself"></td></tr>'
>>> print(f)
<tr><th><label for="id_subject">Subject:</label></th><td><input id="id_subject" type="text" name="subject" maxlength="100" required></td></tr>
<tr><th><label for="id_message">Message:</label></th><td><input type="text" name="message" id="id_message" required></td></tr>
<tr><th><label for="id_sender">Sender:</label></th><td><input type="email" name="sender" id="id_sender" required></td></tr>
<tr><th><label for="id_cc_myself">Cc myself:</label></th><td><input type="checkbox" name="cc_myself" id="id_cc_myself"></td></tr>

所需样式或错误的表单行

Form.error_css_class
Form.required_css_class

对需要或有错误的表单行和字段设置样式是很常见的。例如,您可能希望以粗体显示所需的表单行,并以红色突出显示错误。

这个 Form 类有几个挂钩,您可以用来添加 class 所需行或有错误行的属性:设置 Form.error_css_class 和/或 Form.required_css_class 属性::

from django import forms


class ContactForm(forms.Form):
    error_css_class = "error"
    required_css_class = "required"

    # ... and the rest of your fields here

一旦您这样做了,将给出行 "error" 和/或 "required" 类,视需要而定。该HTML将如下所示:

>>> f = ContactForm(data)
>>> print(f)
<div class="required"><label for="id_subject" class="required">Subject:</label> ...
<div class="required"><label for="id_message" class="required">Message:</label> ...
<div class="required"><label for="id_sender" class="required">Sender:</label> ...
<div><label for="id_cc_myself">Cc myself:</label> ...
>>> f["subject"].label_tag()
<label class="required" for="id_subject">Subject:</label>
>>> f["subject"].legend_tag()
<legend class="required" for="id_subject">Subject:</legend>
>>> f["subject"].label_tag(attrs={"class": "foo"})
<label for="id_subject" class="foo required">Subject:</label>
>>> f["subject"].legend_tag(attrs={"class": "foo"})
<legend for="id_subject" class="foo required">Subject:</legend>

配置表单元素的HTML id 属性和 <label> 标签

Form.auto_id

默认情况下,表单呈现方法包括:

  • HTML id 窗体元素的属性。

  • 相应的 <label> 标签周围的标签。一个HTML <label> 标记指定与哪个表单元素关联的标签文本。这种小的增强使表单更可用,辅助设备也更容易访问。使用它总是个好主意 <label> 标签。

这个 id 属性值是通过预处理生成的 id_ 到窗体域名称。但是,如果要更改 id 约定或删除HTML id 属性和 <label> 完全标签。

使用 auto_id 论据 Form 构造函数来控制 id 和标签行为。此参数必须是 TrueFalse 或字符串。

如果 auto_idFalse ,则表单输出将不包括 <label> 标签或 id 属性:

>>> f = ContactForm(auto_id=False)
>>> print(f)
<div>Subject:<input type="text" name="subject" maxlength="100" required></div>
<div>Message:<textarea name="message" cols="40" rows="10" required></textarea></div>
<div>Sender:<input type="email" name="sender" required></div>
<div>Cc myself:<input type="checkbox" name="cc_myself"></div>

如果 auto_id 设置为 True ,然后表单输出 will 包括 <label> 标记,并将使用该字段名作为其 id 对于每个表单域:

>>> f = ContactForm(auto_id=True)
>>> print(f)
<div><label for="subject">Subject:</label><input type="text" name="subject" maxlength="100" required id="subject"></div>
<div><label for="message">Message:</label><textarea name="message" cols="40" rows="10" required id="message"></textarea></div>
<div><label for="sender">Sender:</label><input type="email" name="sender" required id="sender"></div>
<div><label for="cc_myself">Cc myself:</label><input type="checkbox" name="cc_myself" id="cc_myself"></div>

如果 auto_id 设置为包含格式字符的字符串 '%s' ,则表单输出将包括 <label> 标记,并将生成 id 基于格式字符串的属性。例如,对于格式字符串 'field_%s' ,一个名为 subject 将会得到 id 价值 'field_subject' 。继续我们的示例:

>>> f = ContactForm(auto_id="id_for_%s")
>>> print(f)
<div><label for="id_for_subject">Subject:</label><input type="text" name="subject" maxlength="100" required id="id_for_subject"></div>
<div><label for="id_for_message">Message:</label><textarea name="message" cols="40" rows="10" required id="id_for_message"></textarea></div>
<div><label for="id_for_sender">Sender:</label><input type="email" name="sender" required id="id_for_sender"></div>
<div><label for="id_for_cc_myself">Cc myself:</label><input type="checkbox" name="cc_myself" id="id_for_cc_myself"></div>

如果 auto_id 设置为任何其他真值,例如不包含 %s --那么类库就好像 auto_idTrue .

默认情况下, auto_id 设置为字符串 'id_%s' .

Form.label_suffix

可翻译字符串(默认为冒号 (: )在呈现表单时,将附加在任何标签名称之后。

属性可以自定义或完全省略该字符 label_suffix 参数:

>>> f = ContactForm(auto_id="id_for_%s", label_suffix="")
>>> print(f)
<div><label for="id_for_subject">Subject</label><input type="text" name="subject" maxlength="100" required id="id_for_subject"></div>
<div><label for="id_for_message">Message</label><textarea name="message" cols="40" rows="10" required id="id_for_message"></textarea></div>
<div><label for="id_for_sender">Sender</label><input type="email" name="sender" required id="id_for_sender"></div>
<div><label for="id_for_cc_myself">Cc myself</label><input type="checkbox" name="cc_myself" id="id_for_cc_myself"></div>
>>> f = ContactForm(auto_id="id_for_%s", label_suffix=" ->")
>>> print(f)
<div><label for="id_for_subject">Subject -&gt;</label><input type="text" name="subject" maxlength="100" required id="id_for_subject"></div>
<div><label for="id_for_message">Message -&gt;</label><textarea name="message" cols="40" rows="10" required id="id_for_message"></textarea></div>
<div><label for="id_for_sender">Sender -&gt;</label><input type="email" name="sender" required id="id_for_sender"></div>
<div><label for="id_for_cc_myself">Cc myself -&gt;</label><input type="checkbox" name="cc_myself" id="id_for_cc_myself"></div>

请注意,只有标签的最后一个字符不是标点符号时才会添加标签后缀(在英语中,这些字符是 .!?:

字段还可以定义它们自己的 label_suffix 。这一点将优先于 Form.label_suffix 。后缀也可以在运行时使用 label_suffix 参数设置为 label_tag() / legend_tag()

Form.use_required_attribute

当设置为 True (默认),所需表单域将具有 required HTML属性。

Formsets 用实例化窗体 use_required_attribute=False 以避免在从表单集中添加和删除表单时浏览器验证不正确。

配置窗体小部件的呈现

Form.default_renderer

指定 renderer 用于窗体。默认为 None 这意味着使用 FORM_RENDERER 设置。

在声明窗体或使用 renderer 参数 Form.__init__() . 例如::

from django import forms


class MyForm(forms.Form):
    default_renderer = MyRenderer()

或:

form = MyForm(renderer=MyRenderer())

现场订货注意事项

as_p()as_ul()as_table() 快捷方式时,字段将按照您在表单类中定义它们的顺序显示。比如在 ContactForm 例如,字段按顺序定义 subjectmessagesendercc_myself .要重新排序HTML输出,请更改这些字段在类中的列出顺序。

定制订单还有其他几种方法:

Form.field_order

默认情况下 Form.field_order=None ,它保留您在窗体类中定义字段的顺序。如果 field_order 是字段名列表,字段按列表指定的顺序排列,其余字段按默认顺序追加。忽略列表中的未知字段名。这样就可以通过将子类中的字段设置为 None 不用重新定义顺序。

您也可以使用 Form.field_order 对A的论证 Form 覆盖字段顺序。如果A Form 定义 field_order and 你包括 field_order 当实例化 Form ,然后是后者 field_order 将具有优先权。

Form.order_fields(field_order)

您可以随时使用 order_fields() 字段名列表如中所示 field_order .

错误的显示方式

如果您呈现一个边界 Form 对象时,呈现操作将自动运行窗体的验证(如果尚未进行验证),并且HTML输出将把验证错误作为 <ul class="errorlist"> 在田野附近。错误消息的特定位置取决于您使用的输出方法:

>>> data = {
...     "subject": "",
...     "message": "Hi there",
...     "sender": "invalid email address",
...     "cc_myself": True,
... }
>>> f = ContactForm(data, auto_id=False)
>>> print(f)
<div>Subject:
  <ul class="errorlist"><li>This field is required.</li></ul>
  <input type="text" name="subject" maxlength="100" required aria-invalid="true">
</div>
<div>Message:
  <textarea name="message" cols="40" rows="10" required>Hi there</textarea>
</div>
<div>Sender:
  <ul class="errorlist"><li>Enter a valid email address.</li></ul>
  <input type="email" name="sender" value="invalid email address" required aria-invalid="true">
</div>
<div>Cc myself:
  <input type="checkbox" name="cc_myself" checked>
</div>

自定义错误列表格式

class ErrorList(initlist=None, error_class=None, renderer=None)[源代码]

默认情况下,表单使用 django.forms.utils.ErrorList 若要格式化验证错误,请执行以下操作。 ErrorList 是一个类似列表的对象,其中 initlist 是错误列表。此外,该类还具有以下属性和方法。

error_class

呈现错误列表时要使用的css类。任何提供的类都会添加到默认的 errorlist 班级。

renderer

指定 renderer 用于以下用途 ErrorList 。默认为 None 这意味着使用由 FORM_RENDERER 布景。

template_name

调用时使用的模板的名称 __str__render() 。默认情况下,这是 'django/forms/errors/list/default.html' 的代理,它是 'ul.html' 模板。

template_name_text

调用时使用的模板的名称 as_text() 。默认情况下,这是 'django/forms/errors/list/text.html' 。此模板以项目符号列表的形式呈现错误。

template_name_ul

调用时使用的模板的名称 as_ul() 。默认情况下,这是 'django/forms/errors/list/ul.html' 。此模板在 <li> 带有换行的标签 <ul> 使用由定义的CSS类 error_class

get_context()[源代码]

返回用于在模板中呈现错误的上下文。

可用的上下文为:

  • errors :错误列表。

  • error_class :一串css类。

render(template_name=None, context=None, renderer=None)

Render方法由调用 __str__ 以及由 as_ul() 方法。

所有参数都是可选的,默认为:

as_text()

使用定义的模板呈现错误列表 template_name_text

as_ul()

使用定义的模板呈现错误列表 template_name_ul

如果您想要自定义错误的呈现,可以通过重写 template_name 属性,或者更一般地通过重写默认模板,另请参见 覆盖内置表单模板

更精细的输出

这个 as_p()as_ul() ,以及 as_table() 方法是快捷方式--它们并不是显示表单对象的唯一方式。

class BoundField[源代码]

用于显示单个字段的HTML或访问属性 Form 实例。

这个 __str__() 此对象的方法显示此字段的HTML。

要检索单个 BoundField ,在您的表单上使用字典查找语法,并使用字段名称作为键:

>>> form = ContactForm()
>>> print(form["subject"])
<input id="id_subject" type="text" name="subject" maxlength="100" required>

要检索所有 BoundField 对象,则迭代该表单:

>>> form = ContactForm()
>>> for boundfield in form:
...     print(boundfield)
...
<input id="id_subject" type="text" name="subject" maxlength="100" required>
<input type="text" name="message" id="id_message" required>
<input type="email" name="sender" id="id_sender" required>
<input type="checkbox" name="cc_myself" id="id_cc_myself">

特定于字段的输出遵循Form对象的 auto_id 设置:

>>> f = ContactForm(auto_id=False)
>>> print(f["message"])
<input type="text" name="message" required>
>>> f = ContactForm(auto_id="id_%s")
>>> print(f["message"])
<input type="text" name="message" id="id_message" required>

属性 BoundField

BoundField.auto_id[源代码]

此的html id属性 BoundField . 返回空字符串,如果 Form.auto_idFalse .

BoundField.data[源代码]

此属性返回此 BoundField 由小部件的 value_from_datadict() 方法,或 None 如果它没有被给予:

>>> unbound_form = ContactForm()
>>> print(unbound_form["subject"].data)
None
>>> bound_form = ContactForm(data={"subject": "My Subject"})
>>> print(bound_form["subject"].data)
My Subject
BoundField.errors[源代码]

A list-like object 它显示为一个HTML <ul class="errorlist"> 打印时:

>>> data = {"subject": "hi", "message": "", "sender": "", "cc_myself": ""}
>>> f = ContactForm(data, auto_id=False)
>>> print(f["message"])
<input type="text" name="message" required aria-invalid="true">
>>> f["message"].errors
['This field is required.']
>>> print(f["message"].errors)
<ul class="errorlist"><li>This field is required.</li></ul>
>>> f["subject"].errors
[]
>>> print(f["subject"].errors)

>>> str(f["subject"].errors)
''

在呈现有错误的字段时, aria-invalid="true" 将在字段的窗口小部件上设置,以向屏幕阅读器用户指示存在错误。

BoundField.field

形式 Field 来自窗体类的实例 BoundField 包裹。

BoundField.form

这个 Form 实例如下 BoundField 是必然的。

BoundField.help_text

这个 help_text 田野的

BoundField.html_name

将在小部件的HTML中使用的名称 name 属性。它是这样的 prefix 考虑到。

BoundField.id_for_label[源代码]

使用此属性可呈现此字段的ID。例如,如果要手动构造一个 <label> 在您的模板中(尽管 label_tag()/legend_tag() 将为您做到这一点):

<label for="{{ form.my_field.id_for_label }}">...</label>{{ my_field }}

默认情况下,这将是字段名的前缀为 id_ (上面的示例为“id_my_field`”)。您可以通过设置来修改ID attrs 在字段的小部件上。例如,声明这样的字段:

my_field = forms.CharField(widget=forms.TextInput(attrs={"id": "myFIELD"}))

使用上面的模板,将呈现如下内容:

<label for="myFIELD">...</label><input id="myFIELD" type="text" name="my_field" required>
BoundField.initial[源代码]

使用 BoundField.initial 若要检索表单域的初始数据,请执行以下操作。它从以下位置检索数据 Form.initial 如果存在,则尝试 Field.initial 。评估可调用值。看见 初始表单值 了解更多的例子。

BoundField.initial 缓存其返回值,这在处理返回值可能更改的可计算对象时尤其有用(例如 datetime.nowuuid.uuid4 ):

>>> from datetime import datetime
>>> class DatedCommentForm(CommentForm):
...     created = forms.DateTimeField(initial=datetime.now)
...
>>> f = DatedCommentForm()
>>> f["created"].initial
datetime.datetime(2021, 7, 27, 9, 5, 54)
>>> f["created"].initial
datetime.datetime(2021, 7, 27, 9, 5, 54)

vbl.使用 BoundField.initial 是推荐使用的 get_initial_for_field()

BoundField.is_hidden[源代码]

返回 True 如果这样 BoundField 的小部件被隐藏。

BoundField.label

这个 label of the field. This is used in label_tag()/legend_tag()

BoundField.name

表单中此字段的名称:

>>> f = ContactForm()
>>> print(f["subject"].name)
subject
>>> print(f["message"].name)
message
BoundField.template_name[源代码]

使用呈现的模板的名称 BoundField.as_field_group()

属性,该属性返回 template_name 如果设置为其他值 field_template_name

BoundField.use_fieldset[源代码]

返回此边界字段小工具的 use_fieldset 属性。

BoundField.widget_type[源代码]

返回包装字段的微件的小写类名,并带有任何尾随 inputwidget 已删除。这可以在构建布局依赖于小部件类型的表单时使用。例如:

{% for field in form %}
    {% if field.widget_type == 'checkbox' %}
        # render one way
    {% else %}
        # render another way
    {% endif %}
{% endfor %}

方法 BoundField

BoundField.as_field_group()

使用以下命令呈现该字段 BoundField.render() 具有缺省值,从而呈现 BoundField ,包括其标签、帮助文本和使用模板的 template_name 如果设置为其他值 field_template_name

BoundField.as_hidden(attrs=None, **kwargs)[源代码]

返回一个HTML字符串,用于将其表示为 <input type="hidden"> .

**kwargs 被传递给 as_widget() .

这种方法主要在内部使用。您应该改为使用小部件。

BoundField.as_widget(widget=None, attrs=None, only_initial=False)[源代码]

通过呈现传递的小部件来呈现字段,添加作为 attrs . 如果没有指定小部件,那么将使用字段的默认小部件。

only_initial 由Django内部使用,不应显式设置。

BoundField.css_classes(extra_classes=None)[源代码]

当您使用Django的呈现快捷键时,将使用CSS类来指示必需的表单域或包含错误的域。如果要手动呈现窗体,则可以使用 css_classes 方法:

>>> f = ContactForm(data={"message": ""})
>>> f["message"].css_classes()
'required'

如果除了可能需要的错误和必需类之外,您还想提供一些其他类,则可以将这些类作为参数提供:

>>> f = ContactForm(data={"message": ""})
>>> f["message"].css_classes("foo bar")
'foo bar required'
BoundField.get_context()[源代码]

返回用于呈现该字段的模板上下文。可用的上下文为 field 是绑定字段的实例。

BoundField.label_tag(contents=None, attrs=None, label_suffix=None, tag=None)[源代码]

使用由指定的模板呈现表单域的标签标记 Form.template_name_label

可用的上下文为:

  • field :此实例为 BoundField

  • contents :默认情况下,连接的字符串为 BoundField.labelForm.label_suffix (或 Field.label_suffix ,如果已设置)。这可以由 contentslabel_suffix 争论。

  • attrs :A dictforForm.required_css_class ,以及 idid 由字段的微件生成 attrsBoundField.auto_id 。其他属性可以由 attrs 争论。

  • use_tag :布尔值,它是 True 如果标签有一个 id 。如果 False 默认模板省略了 tag

  • tag :用于自定义标记的可选字符串,默认为 label

小技巧

在您的模板中 field 是对象的实例 BoundField 。因此 field.field 访问 BoundField.field 作为您声明的字段,例如 forms.CharField

若要单独呈现表单域的标签标记,可以调用其 label_tag() 方法:

>>> f = ContactForm(data={"message": ""})
>>> print(f["message"].label_tag())
<label for="id_message">Message:</label>

如果想要自定义呈现,可以通过重写 Form.template_name_label 属性,或者更一般地通过重写默认模板,另请参见 覆盖内置表单模板

BoundField.legend_tag(contents=None, attrs=None, label_suffix=None)[源代码]

打电话 label_tag() 使用 tag='legend' 用来呈现标签的步骤 <legend> 标签。这在呈现单选和多个复选框小部件时非常有用 <legend> 可能比 <label>

BoundField.render(template_name=None, context=None, renderer=None)

Render方法由调用 as_field_group 。所有参数都是可选的,默认为:

通过路过 template_name 您可以自定义仅用于单个呼叫的模板。

BoundField.value()[源代码]

使用此方法呈现该字段的原始值,就像它将由 Widget

>>> initial = {"subject": "welcome"}
>>> unbound_form = ContactForm(initial=initial)
>>> bound_form = ContactForm(data={"subject": "hi"}, initial=initial)
>>> print(unbound_form["subject"].value())
welcome
>>> print(bound_form["subject"].value())
hi

定制 BoundField

如果需要访问有关模板中表单字段的一些附加信息并使用 Field 不够,还可以考虑定制 BoundField .

自定义表单域可以重写 get_bound_field()

Field.get_bound_field(form, field_name)[源代码]

以…为例 Form 以及字段的名称。访问模板中的字段时将使用返回值。很可能是 BoundField .

如果你有 GPSCoordinatesField 例如,如果希望能够访问有关模板中坐标的其他信息,可以按以下方式实现:

class GPSCoordinatesBoundField(BoundField):
    @property
    def country(self):
        """
        Return the country the coordinates lie in or None if it can't be
        determined.
        """
        value = self.value()
        if value:
            return get_country_from_coordinates(value)
        else:
            return None


class GPSCoordinatesField(Field):
    def get_bound_field(self, form, field_name):
        return GPSCoordinatesBoundField(form, self, field_name)

现在,您可以使用 {{{{ form.coordinates.country }}}} .

将上载的文件绑定到表单

处理具有 FileFieldImageField 字段比普通形式稍微复杂一点。

首先,为了上传文件,您需要确保您的 <form> 元素正确地定义了 enctype AS "multipart/form-data"

<form enctype="multipart/form-data" method="post" action="/foo/">

其次,在使用表单时,需要绑定文件数据。文件数据与普通表单数据分开处理,因此当您的表单包含 FileFieldImageField ,则在绑定窗体时需要指定第二个参数。因此,如果我们将ContactForm扩展为包含一个 ImageField 被呼叫 mugshot ,我们需要绑定包含大头照图片的文件数据:

# Bound form with an image field
>>> from django.core.files.uploadedfile import SimpleUploadedFile
>>> data = {
...     "subject": "hello",
...     "message": "Hi there",
...     "sender": "foo@example.com",
...     "cc_myself": True,
... }
>>> file_data = {"mugshot": SimpleUploadedFile("face.jpg", b"file data")}
>>> f = ContactFormWithMugshot(data, file_data)

实际上,您通常会指定 request.FILES 作为文件数据的源(就像使用 request.POST 作为表单数据的来源):

# Bound form with an image field, data from the request
>>> f = ContactFormWithMugshot(request.POST, request.FILES)

构造未绑定的表单与以往一样--省略两个表单数据 and 文件数据:

# Unbound form with an image field
>>> f = ContactFormWithMugshot()

多部分表单测试

Form.is_multipart()

如果您正在编写可重用的视图或模板,您可能无法提前知道您的表单是否为多部分表单。这个 is_multipart() 方法告诉您表单是否需要多部分编码才能提交:

>>> f = ContactFormWithMugshot()
>>> f.is_multipart()
True

下面是一个如何在模板中使用它的示例:

{% if form.is_multipart %}
    <form enctype="multipart/form-data" method="post" action="/foo/">
{% else %}
    <form method="post" action="/foo/">
{% endif %}
{{ form }}
</form>

子类化形式

如果你有多个 Form 类共享字段,您可以使用子类来消除冗余。

当您将自定义 Form 类,生成的子类将包括父类的所有字段,然后是子类中定义的字段。

在本例中, ContactFormWithPriority 包含来自的所有字段 ContactForm ,外加一个额外的字段, priority 。这个 ContactForm 首先对字段进行排序:

>>> class ContactFormWithPriority(ContactForm):
...     priority = forms.CharField()
...
>>> f = ContactFormWithPriority(auto_id=False)
>>> print(f)
<div>Subject:<input type="text" name="subject" maxlength="100" required></div>
<div>Message:<textarea name="message" cols="40" rows="10" required></textarea></div>
<div>Sender:<input type="email" name="sender" required></div>
<div>Cc myself:<input type="checkbox" name="cc_myself"></div>
<div>Priority:<input type="text" name="priority" required></div>

可以细分多个Form,将Form视为混合。在本例中, BeatleForm 子类和子类 PersonFormInstrumentForm (按该顺序),其字段列表包括来自父类的字段:

>>> from django import forms
>>> class PersonForm(forms.Form):
...     first_name = forms.CharField()
...     last_name = forms.CharField()
...
>>> class InstrumentForm(forms.Form):
...     instrument = forms.CharField()
...
>>> class BeatleForm(InstrumentForm, PersonForm):
...     haircut_type = forms.CharField()
...
>>> b = BeatleForm(auto_id=False)
>>> print(b)
<div>First name:<input type="text" name="first_name" required></div>
<div>Last name:<input type="text" name="last_name" required></div>
<div>Instrument:<input type="text" name="instrument" required></div>
<div>Haircut type:<input type="text" name="haircut_type" required></div>

可以声明性地移除 Field 通过将字段名称设置为从父类继承 None 在子类上。例如:

>>> from django import forms

>>> class ParentForm(forms.Form):
...     name = forms.CharField()
...     age = forms.IntegerField()
...

>>> class ChildForm(ParentForm):
...     name = None
...

>>> list(ChildForm().fields)
['age']

表单的前缀

Form.prefix

您可以将几个Django表单放在一个表单中 <form> 标签。给每个人 Form 它自己的命名空间,请使用 prefix 关键字参数:

>>> mother = PersonForm(prefix="mother")
>>> father = PersonForm(prefix="father")
>>> print(mother)
<div><label for="id_mother-first_name">First name:</label><input type="text" name="mother-first_name" required id="id_mother-first_name"></div>
<div><label for="id_mother-last_name">Last name:</label><input type="text" name="mother-last_name" required id="id_mother-last_name"></div>
>>> print(father)
<div><label for="id_father-first_name">First name:</label><input type="text" name="father-first_name" required id="id_father-first_name"></div>
<div><label for="id_father-last_name">Last name:</label><input type="text" name="father-last_name" required id="id_father-last_name"></div>

前缀也可以在Form类上指定:

>>> class PersonForm(forms.Form):
...     ...
...     prefix = "person"
...