Forms API¶
关于本文档
本文档涵盖了Django的表单API的细节。你应该先阅读 介绍使用表单。
绑定和未绑定的形式¶
Form
实例是 界 到一组数据,或 未绑定。
如果它是一组数据的 界,它能够验证该数据,并将表单作为HTML显示在HTML中的数据呈现。
如果是 未绑定,它不能做验证(因为没有数据要验证!),但它仍然可以将空白表单呈现为HTML。
要创建一个未绑定的 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
()¶
当您必须为相互依赖的字段添加自定义验证时,在您的 Form
上实施 clean()
方法。有关使用示例,请参阅 清洁和验证彼此依赖的字段。
-
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.']}
在此字典中,键是字段名称,值是表示错误消息的Unicode字符串列表。错误消息存储在列表中,因为字段可以有多个错误消息。
您可以访问 errors
,而无需先调用 is_valid()
。表格的数据将在您第一次调用 is_valid()
或访问 errors
时验证。
验证例程将只调用一次,无论您访问 errors
或调用 is_valid()
的次数。这意味着如果验证有副作用,那些副作用只会被触发一次。
-
Form.errors.
as_data
()¶
返回将字段映射到其原始 ValidationError
实例的 dict
。
>>> 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库(如jQuery)这样做很简单 - 只需使用 $(el).text(errorText)
,而不是 .html()
。
如果由于某些原因你不想使用客户端转义,你也可以设置 escape_html=True
和错误消息将被转义,所以你可以直接在HTML中使用它们。
-
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
的错误。如果 code
是 None
,如果字段包含任何错误,它将返回 True
。
要检查非字段错误,请使用 NON_FIELD_ERRORS
作为 field
参数。
-
Form.
non_field_errors
()¶
此方法返回 Form.errors
中与特定字段不相关联的错误列表。这包括在 Form.clean()
中引发的 ValidationError
和使用 Form.add_error(None, "...")
添加的错误。
未绑定表单的行为¶
验证没有数据的表单是无意义的,但是对于记录,这里是未绑定表单发生的情况:
>>> f = ContactForm()
>>> f.is_valid()
False
>>> f.errors
{}
动态初始值¶
-
Form.
initial
¶
使用 initial
在运行时声明表单字段的初始值。例如,您可能需要使用当前会话的用户名填写 username
字段。
要完成此操作,请对 Form
使用 initial
参数。这个参数,如果给定,应该是字段映射字段名称到初始值。只包括您要为其指定初始值的字段;它不必包括您的表单中的每个字段。例如:
>>> f = ContactForm(initial={'subject': 'Hi there!'})
这些值仅针对未绑定的表单显示,如果未提供特定值,则不会用作回退值。
如果 Field
定义 initial
and,则在实例化 Form
时包括 initial
,则后者 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.
has_changed
()¶
当您需要检查表单数据是否已从初始数据更改时,在您的 Form
上使用 has_changed()
方法。
>>> 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()
如果来自 request.POST
的数据不同于 initial
或 False
中提供的数据,则 has_changed()
将是 True
。通过为表单中的每个字段调用 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))
从表单访问字段¶
-
Form.
fields
¶
您可以从其 fields
属性访问 Form
实例的字段:
>>> 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
属性,因为此修改将影响同一个Python进程中的所有后续 ContactForm
实例:
>>> 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
¶
Form
类中的每个字段不仅负责验证数据,还负责“清理”它 - 将其标准化为一致的格式。这是一个很好的功能,因为它允许以各种方式输入特定字段的数据,总是导致一致的输出。
例如,DateField
将输入规范化为Python datetime.date
对象。无论你是传递一个格式为 '1994-07-15'
,datetime.date
对象还是许多其他格式的字符串,只要 DateField
有效,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'}
请注意,任何基于文本的字段(例如 CharField
或 EmailField
)始终将输入清除为Unicode字符串。我们将在本文后面介绍编码的含义。
如果您的数据被 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_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'}
在上面的示例中,nick_name
的 cleaned_data
值设置为空字符串,因为 nick_name
是 CharField
,CharField
将空值视为空字符串。每个字段类型知道它的“空白”值是什么 - 例如,对于 DateField
,它是 None
而不是空字符串。有关这种情况下每个字段行为的完整详细信息,请参阅下面“内置 Field
类”部分中每个字段的“空值”注释。
您可以编写代码以对特定表单字段(基于其名称)或表单作为整体(考虑各种字段的组合)执行验证。有关这方面的更多信息是在 表单和字段验证。
将表单输出为HTML¶
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="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="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>
标记包含在输出中,以遵循最佳做法,但您可以更改此行为。
虽然 <table>
输出是默认输出样式,当您 print
一个窗体,其他输出样式可用。每个样式可用作表单对象上的方法,每个呈现方法都返回一个Unicode对象。
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>
上指定任何HTML属性以提高灵活性:
>>> 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>
标记,则此行为是可配置的。
使用 Form
构造函数的 auto_id
参数来控制 id
和标签行为。此参数必须是 True
,False
或字符串。
如果 auto_id
是 False
,则表单输出将不包括 <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_id
是 True
。
默认情况下,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属性。
表单 用 use_required_attribute=False
实例化表单,以避免在从表单集中添加和删除表单时不正确的浏览器验证。
字段排序注释¶
在 as_p()
,as_ul()
和 as_table()
快捷方式中,字段按您在表单类中定义的顺序显示。例如,在 ContactForm
示例中,字段以 subject
,message
,sender
,cc_myself
的顺序定义。要重新排序HTML输出,只需更改类中列出这些字段的顺序。
还有其他几种自定义顺序的方法:
-
Form.
field_order
¶
默认情况下为 Form.field_order=None
,它保留在窗体类中定义字段的顺序。如果 field_order
是字段名称列表,则字段按列表指定排序,其余字段根据默认顺序附加。列表中未知的字段名称将被忽略。这使得可以通过将其设置为 None
而禁用子类中的字段,而无需重新定义排序。
您还可以使用 Form
的 Form.field_order
参数覆盖字段顺序。如果 Form
定义 field_order
and,则在实例化 Form
时包括 field_order
,则后者的 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="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="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="checked" type="checkbox" name="cc_myself" /></p>
自定义错误列表格式¶
默认情况下,表单使用 django.forms.utils.ErrorList
格式化验证错误。如果你想使用一个替代类来显示错误,你可以在构建时传递(在Python 2上用 __unicode__
替换 __str__
):
>>> from django.forms.utils import ErrorList
>>> class DivErrorList(ErrorList):
... def __str__(self): # __unicode__ on Python 2
... 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="checked" type="checkbox" name="cc_myself" /></p>
更细粒度的输出¶
as_p()
,as_ul()
和 as_table()
方法只是简单的快捷方式 - 它们不是可以显示表单对象的唯一方式。
要检索单个 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
¶ 此
BoundField
的HTML ID属性。如果Form.auto_id
是False
,则返回空字符串。
-
BoundField.
data
¶ 此属性返回由窗口小部件的
value_from_datadict()
方法提取的此BoundField
的数据,如果未提供,则返回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
¶ 打印时显示为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
¶ 来自此
BoundField
包装的表单类的Field
实例。
-
BoundField.
form
¶ 绑定到该
BoundField
的Form
实例。
-
BoundField.
id_for_label
¶ 使用此属性呈现此字段的ID。例如,如果您在模板中手动构建
<label>
(尽管label_tag()
会为您执行此操作):<label for="{{ form.my_field.id_for_label }}">...</label>{{ my_field }}
默认情况下,这将是字段的名称前缀为
id_
(上面的例子中为“id_my_field
”)。您可以通过在字段的小部件上设置attrs
来修改ID。例如,声明一个这样的字段:my_field = forms.CharField(widget=forms.TextInput(attrs={'id': 'myFIELD'}))
并使用上面的模板,将呈现如下:
<label for="myFIELD">...</label><input id="myFIELD" type="text" name="my_field" required />
如果此
BoundField
的窗口小部件被隐藏,则返回True
。
-
BoundField.
label
¶ 领域的
label
。这用于label_tag()
。
-
BoundField.
name
¶ 表单中此字段的名称:
>>> f = ContactForm() >>> print(f['subject'].name) subject >>> print(f['message'].name) message
BoundField
方法¶
返回一个HTML字符串,用于将其表示为
<input type="hidden">
。**kwargs
传递给as_widget()
。此方法主要在内部使用。你应该使用一个小部件。
-
BoundField.
as_widget
(widget=None, attrs=None, only_initial=False)¶ 通过呈现传递的窗口小部件,添加作为
attrs
传递的任何HTML属性来呈现字段。如果未指定任何窗口小部件,则将使用字段的默认窗口小部件。only_initial
由Django内部使用,不应明确设置。
-
BoundField.
css_classes
()¶ 当您使用Django的呈现快捷方式时,CSS类用于指示必需的表单字段或包含错误的字段。如果你手动渲染表单,你可以使用
css_classes
方法访问这些CSS类:>>> 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 }}
在模板中访问国家/地区。
将上传的文件绑定到表单¶
处理具有 FileField
和 ImageField
字段的表单比正常表单更复杂一些。
首先,为了上传文件,您需要确保您的 <form>
元素将 enctype
正确定义为 "multipart/form-data"
:
<form enctype="multipart/form-data" method="post" action="/foo/">
其次,当您使用表单时,需要绑定文件数据。文件数据与正常表单数据分开处理,因此,当您的表单包含 FileField
和 ImageField
时,您需要在绑定表单时指定第二个参数。因此,如果我们扩展ContactForm以包括一个名为 mugshot
的 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>
可以将多个表单子类化,将表单视为mixin。在此示例中,BeatleForm
将 PersonForm
和 InstrumentForm
(按此顺序)子类化,其字段列表包括父类的字段:
>>> 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>
可以通过将字段的名称设置为子类上的 None
来声明性地删除从父类继承的 Field
。例如:
>>> from django import forms
>>> class ParentForm(forms.Form):
... name = forms.CharField()
... age = forms.IntegerField()
>>> class ChildForm(ParentForm):
... name = None
>>> ChildForm().fields.keys()
... ['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'
添加了在表单类上指定 prefix
的功能。