Django 2.2.4.dev20190701100356 文档

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

请注意,传递空字典将创建 跳跃 包含空数据的表单::

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

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

使用表单验证数据

Form.clean()

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

Form.is_valid()

A的主要任务 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请求的表单视图,在该视图中,客户机解释响应并将错误插入页面,那么您一定要避开客户机端的结果,以避免发生跨站点脚本攻击的可能性。使用jquery这样的javascript库是很简单的-只需使用 $(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 对A的论证 Form . 此参数(如果给定)应该是将字段名映射到初始值的字典。只包括要为其指定初始值的字段;不必包括表单中的每个字段。例如::

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

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

如果A Field 定义 initial and 你包括 initial 当实例化 Form ,然后是后者 initial 将具有优先权。在这个例子中, initial 同时在字段级别和表单实例级别提供,后者获得优先级:

>>> 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)
<tr><th>Name:</th><td><input type="text" name="name" value="instance" required></td></tr>
<tr><th>Url:</th><td><input type="url" name="url" required></td></tr>
<tr><th>Comment:</th><td><input type="text" name="comment" required></td></tr>
Form.get_initial_for_field(field, field_name)

使用 get_initial_for_field() 检索窗体字段的初始数据。它从 Form.initialField.initial ,并计算任何可调用的初始值。

检查哪个表单数据已更改

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 其实例 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>

你可以改变 Form 更改表单中呈现方式的实例:

>>> f.as_table().split('\n')[0]
'<tr><th>Name:</th><td><input name="name" type="text" value="instance" required></td></tr>'
>>> f.fields['name'].label = "Username"
>>> f.as_table().split('\n')[0]
'<tr><th>Username:</th><td><input name="name" type="text" value="instance" required></td></tr>'

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

>>> f.base_fields['name'].label = "Username"
>>> another_f = CommentForm(auto_id=False)
>>> another_f.as_table().split('\n')[0]
'<tr><th>Username:</th><td><input name="name" type="text" value="class" required></td></tr>'

访问“干净”数据

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 将永远 only 包含在中定义的字段的键 Form ,即使在定义 Form . 在这个例子中,我们向 ContactForm 建造师,但是 cleaned_data 仅包含表单的字段::

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

A的第二个任务 Form 对象将自身呈现为HTML。这样做,很简单 print 它::

>>> f = ContactForm()
>>> 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>

如果表单绑定到数据,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)
<tr><th><label for="id_subject">Subject:</label></th><td><input id="id_subject" type="text" name="subject" maxlength="100" value="hello" required></td></tr>
<tr><th><label for="id_message">Message:</label></th><td><input type="text" name="message" id="id_message" value="Hi there" required></td></tr>
<tr><th><label for="id_sender">Sender:</label></th><td><input type="email" name="sender" id="id_sender" value="foo@example.com" 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" checked></td></tr>

此默认输出为两列HTML表,其中 <tr> 对于每个字段。注意以下事项:

  • 为了灵活性,输出 not 包括 <table></table> 标签,也不包括 <form></form> 标签或 <input type="submit"> 标签。这是你的工作。
  • 每个字段类型都有一个默认的HTML表示形式。 CharField 表示为 <input type="text">EmailField 由一个 <input type="email"> . BooleanField 表示为 <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' .

虽然 <table> 输出是默认的输出样式, print 一个窗体,其他输出样式可用。每个样式都可以作为窗体对象上的方法使用,并且每个呈现方法都返回一个字符串。

as_p()

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.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.as_table()

最后, as_table() 以HTML形式输出表单 <table> . 这和 print . 事实上,当你 print 窗体对象,它调用 as_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.as_table())
<tr class="required"><th><label class="required" for="id_subject">Subject:</label>    ...
<tr class="required"><th><label class="required" for="id_message">Message:</label>    ...
<tr class="required error"><th><label class="required" for="id_sender">Sender:</label>      ...
<tr><th><label for="id_cc_myself">Cc myself:<label> ...
>>> f['subject'].label_tag()
<label class="required" for="id_subject">Subject:</label>
>>> f['subject'].label_tag(attrs={'class': 'foo'})
<label for="id_subject" class="foo required">Subject:</label>

配置表单元素的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.as_table())
<tr><th>Subject:</th><td><input type="text" name="subject" maxlength="100" required></td></tr>
<tr><th>Message:</th><td><input type="text" name="message" required></td></tr>
<tr><th>Sender:</th><td><input type="email" name="sender" required></td></tr>
<tr><th>Cc myself:</th><td><input type="checkbox" name="cc_myself"></td></tr>
>>> print(f.as_ul())
<li>Subject: <input type="text" name="subject" maxlength="100" required></li>
<li>Message: <input type="text" name="message" required></li>
<li>Sender: <input type="email" name="sender" required></li>
<li>Cc myself: <input type="checkbox" name="cc_myself"></li>
>>> print(f.as_p())
<p>Subject: <input type="text" name="subject" maxlength="100" required></p>
<p>Message: <input type="text" name="message" required></p>
<p>Sender: <input type="email" name="sender" required></p>
<p>Cc myself: <input type="checkbox" name="cc_myself"></p>

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

>>> f = ContactForm(auto_id=True)
>>> print(f.as_table())
<tr><th><label for="subject">Subject:</label></th><td><input id="subject" type="text" name="subject" maxlength="100" required></td></tr>
<tr><th><label for="message">Message:</label></th><td><input type="text" name="message" id="message" required></td></tr>
<tr><th><label for="sender">Sender:</label></th><td><input type="email" name="sender" id="sender" required></td></tr>
<tr><th><label for="cc_myself">Cc myself:</label></th><td><input type="checkbox" name="cc_myself" id="cc_myself"></td></tr>
>>> print(f.as_ul())
<li><label for="subject">Subject:</label> <input id="subject" type="text" name="subject" maxlength="100" required></li>
<li><label for="message">Message:</label> <input type="text" name="message" id="message" required></li>
<li><label for="sender">Sender:</label> <input type="email" name="sender" id="sender" required></li>
<li><label for="cc_myself">Cc myself:</label> <input type="checkbox" name="cc_myself" id="cc_myself"></li>
>>> print(f.as_p())
<p><label for="subject">Subject:</label> <input id="subject" type="text" name="subject" maxlength="100" required></p>
<p><label for="message">Message:</label> <input type="text" name="message" id="message" required></p>
<p><label for="sender">Sender:</label> <input type="email" name="sender" id="sender" required></p>
<p><label for="cc_myself">Cc myself:</label> <input type="checkbox" name="cc_myself" id="cc_myself"></p>

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

>>> f = ContactForm(auto_id='id_for_%s')
>>> print(f.as_table())
<tr><th><label for="id_for_subject">Subject:</label></th><td><input id="id_for_subject" type="text" name="subject" maxlength="100" required></td></tr>
<tr><th><label for="id_for_message">Message:</label></th><td><input type="text" name="message" id="id_for_message" required></td></tr>
<tr><th><label for="id_for_sender">Sender:</label></th><td><input type="email" name="sender" id="id_for_sender" required></td></tr>
<tr><th><label for="id_for_cc_myself">Cc myself:</label></th><td><input type="checkbox" name="cc_myself" id="id_for_cc_myself"></td></tr>
>>> print(f.as_ul())
<li><label for="id_for_subject">Subject:</label> <input id="id_for_subject" type="text" name="subject" maxlength="100" required></li>
<li><label for="id_for_message">Message:</label> <input type="text" name="message" id="id_for_message" required></li>
<li><label for="id_for_sender">Sender:</label> <input type="email" name="sender" id="id_for_sender" required></li>
<li><label for="id_for_cc_myself">Cc myself:</label> <input type="checkbox" name="cc_myself" id="id_for_cc_myself"></li>
>>> print(f.as_p())
<p><label for="id_for_subject">Subject:</label> <input id="id_for_subject" type="text" name="subject" maxlength="100" required></p>
<p><label for="id_for_message">Message:</label> <input type="text" name="message" id="id_for_message" required></p>
<p><label for="id_for_sender">Sender:</label> <input type="email" name="sender" id="id_for_sender" required></p>
<p><label for="id_for_cc_myself">Cc myself:</label> <input type="checkbox" name="cc_myself" id="id_for_cc_myself"></p>

如果 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.as_ul())
<li><label for="id_for_subject">Subject</label> <input id="id_for_subject" type="text" name="subject" maxlength="100" required></li>
<li><label for="id_for_message">Message</label> <input type="text" name="message" id="id_for_message" required></li>
<li><label for="id_for_sender">Sender</label> <input type="email" name="sender" id="id_for_sender" required></li>
<li><label for="id_for_cc_myself">Cc myself</label> <input type="checkbox" name="cc_myself" id="id_for_cc_myself"></li>
>>> f = ContactForm(auto_id='id_for_%s', label_suffix=' ->')
>>> print(f.as_ul())
<li><label for="id_for_subject">Subject -></label> <input id="id_for_subject" type="text" name="subject" maxlength="100" required></li>
<li><label for="id_for_message">Message -></label> <input type="text" name="message" id="id_for_message" required></li>
<li><label for="id_for_sender">Sender -></label> <input type="email" name="sender" id="id_for_sender" required></li>
<li><label for="id_for_cc_myself">Cc myself -></label> <input type="checkbox" name="cc_myself" id="id_for_cc_myself"></li>

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

字段还可以定义自己的 label_suffix . 这将优先于 Form.label_suffix . 也可以在运行时使用 label_suffix 参数到 label_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.as_table())
<tr><th>Subject:</th><td><ul class="errorlist"><li>This field is required.</li></ul><input type="text" name="subject" maxlength="100" required></td></tr>
<tr><th>Message:</th><td><input type="text" name="message" value="Hi there" required></td></tr>
<tr><th>Sender:</th><td><ul class="errorlist"><li>Enter a valid email address.</li></ul><input type="email" name="sender" value="invalid email address" required></td></tr>
<tr><th>Cc myself:</th><td><input checked type="checkbox" name="cc_myself"></td></tr>
>>> print(f.as_ul())
<li><ul class="errorlist"><li>This field is required.</li></ul>Subject: <input type="text" name="subject" maxlength="100" required></li>
<li>Message: <input type="text" name="message" value="Hi there" required></li>
<li><ul class="errorlist"><li>Enter a valid email address.</li></ul>Sender: <input type="email" name="sender" value="invalid email address" required></li>
<li>Cc myself: <input checked type="checkbox" name="cc_myself"></li>
>>> print(f.as_p())
<p><ul class="errorlist"><li>This field is required.</li></ul></p>
<p>Subject: <input type="text" name="subject" maxlength="100" required></p>
<p>Message: <input type="text" name="message" value="Hi there" required></p>
<p><ul class="errorlist"><li>Enter a valid email address.</li></ul></p>
<p>Sender: <input type="email" name="sender" value="invalid email address" required></p>
<p>Cc myself: <input checked type="checkbox" name="cc_myself"></p>

自定义错误列表格式

默认情况下,表单使用 django.forms.utils.ErrorList 设置验证错误的格式。如果要使用替换类来显示错误,可以在构造时将其传入:

>>> from django.forms.utils import ErrorList
>>> class DivErrorList(ErrorList):
...     def __str__(self):
...         return self.as_divs()
...     def as_divs(self):
...         if not self: return ''
...         return '<div class="errorlist">%s</div>' % ''.join(['<div class="error">%s</div>' % e for e in self])
>>> f = ContactForm(data, auto_id=False, error_class=DivErrorList)
>>> f.as_p()
<div class="errorlist"><div class="error">This field is required.</div></div>
<p>Subject: <input type="text" name="subject" maxlength="100" required></p>
<p>Message: <input type="text" name="message" value="Hi there" required></p>
<div class="errorlist"><div class="error">Enter a valid email address.</div></div>
<p>Sender: <input type="email" name="sender" value="invalid email address" required></p>
<p>Cc myself: <input checked type="checkbox" name="cc_myself"></p>

更精细的输出

这个 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">

字段特定的输出符合窗体对象的 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>
>>> 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)
''
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() 将为您执行此操作):

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

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

BoundField.label

这个 label 田野的这是用在 label_tag() .

BoundField.name

表单中此字段的名称:

>>> f = ContactForm()
>>> print(f['subject'].name)
subject
>>> print(f['message'].name)
message

方法 BoundField

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()[源代码]

使用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.label_tag(contents=None, attrs=None, label_suffix=None)[源代码]

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

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

您可以提供 contents 将替换自动生成的标签标记的参数。安 attrs 字典可能包含 <label> 标签。

生成的HTML包括表单的 label_suffix (默认为冒号)或(如果设置了)当前字段的 label_suffix . 可选的 label_suffix 参数允许您覆盖以前设置的任何后缀。例如,可以使用空字符串隐藏所选字段上的标签。如果需要在模板中执行此操作,可以编写自定义筛选器以允许将参数传递到 label_tag .

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 作为 "multipart/form-data" ::

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

其次,使用表单时,需要绑定文件数据。文件数据与普通表单数据分开处理,因此当表单包含 FileFieldImageField ,绑定表单时需要指定第二个参数。所以如果我们扩展我们的联系人表单以包括 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', <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.as_ul())
<li>Subject: <input type="text" name="subject" maxlength="100" required></li>
<li>Message: <input type="text" name="message" required></li>
<li>Sender: <input type="email" name="sender" required></li>
<li>Cc myself: <input type="checkbox" name="cc_myself"></li>
<li>Priority: <input type="text" name="priority" required></li>

可以将多个表单分为多个子类,将表单视为混合体。在这个例子中, 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.as_ul())
<li>First name: <input type="text" name="first_name" required></li>
<li>Last name: <input type="text" name="last_name" required></li>
<li>Instrument: <input type="text" name="instrument" required></li>
<li>Haircut type: <input type="text" name="haircut_type" required></li>

可以声明性地删除 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.as_ul())
<li><label for="id_mother-first_name">First name:</label> <input type="text" name="mother-first_name" id="id_mother-first_name" required></li>
<li><label for="id_mother-last_name">Last name:</label> <input type="text" name="mother-last_name" id="id_mother-last_name" required></li>
>>> print(father.as_ul())
<li><label for="id_father-first_name">First name:</label> <input type="text" name="father-first_name" id="id_father-first_name" required></li>
<li><label for="id_father-last_name">Last name:</label> <input type="text" name="father-last_name" id="id_father-last_name" required></li>

也可以在表单类上指定前缀::

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