当前位置

网站首页> 程序设计 > 开源项目 > 程序开发 > 浏览文章

django 1.8 官方文档翻译:5-1-2 表单API

作者:小梦 来源: 网络 时间: 2024-04-27 阅读:

表单 API

关于这篇文档

这篇文档讲述Django 表单API 的详细细节。你应该先阅读_表单简介_。

绑定的表单和未绑定的表单

表单要么是绑定的,要么是未绑定的

_class _Form

若要创建一个未绑定的表单实例,只需简单地实例化该类:

>>> f = ContactForm()

若要绑定数据到表单,可以将数据以字典的形式传递给表单类的构造函数的第一个参数:

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

在这个字典中,键为字段的名称,它们对应于表单类中的属性。值为需要验证的数据。它们通常为字符串,但是没有强制要求必须是字符串;传递的数据类型取决于字段,我们稍后会看到。

Form.`is_bound`

如果运行时刻你需要区分绑定的表单和未绑定的表单,可以检查下表单is_bound 属性的值:

>>> f = ContactForm()>>> f.is_boundFalse>>> f = ContactForm({'subject': 'hello'})>>> f.is_boundTrue

注意,传递一个空的字典将创建一个带有空数据的_绑定的_表单:

>>> f = ContactForm({})>>> f.is_boundTrue

如果你有一个绑定的表单实例但是想改下数据,或者你想绑定一个未绑定的表单表单到某些数据,你需要创建另外一个表单实例。Form 实例的数据没有办法修改。表单实例一旦创建,你应该将它的数据视为不可变的,无论它有没有数据。

使用表单来验证数据

Form.`clean`()

当你需要为相互依赖的字段添加自定义的验证时,你可以实现表单clean()方法。示例用法参见_Cleaning and validating fields that depend on each other_。

Form.`is_valid`()

表单对象的首要任务就是验证数据。对于绑定的表单实例,可以调用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 字符串组成的列表。错误信息保存在列表中是因为字段可能有多个错误信息。

你可以在调用is_valid()?之前访问errors。表单的数据将在第一次调用is_valid() 或者访问errors 时验证。

验证将值调用一次,无论你访问errors 或者调用is_valid() 多少次。这意味着,如果验证过程有副作用,这些副作用将只触发一次。

Form.errors.`as_data`()

New in Django 1.7\.

返回一个字典,它映射字段到原始的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_)

New in Django 1.7\.

返回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_)

New in Django 1.7\.

这个方法允许在Form.clean() 方法内部或从表单的外部一起给字段添加错误信息;例如从一个视图中。

field 参数为字段的名称。如果值为None,error 将作为Form.non_field_errors() 返回的一个非字段错误。

error 参数可以是一个简单的字符串,或者最好是一个ValidationError 实例。_引发ValidationError_ 中可以看到定义表单错误时的最佳实践。

注意,Form.add_error() 会自动删除cleaned_data 中的相关字段。

Form.`has_error`(_field_, _code=None_)

New in Django 1.8\.

这个方法返回一个布尔值,指示一个字段是否具有指定错误code 的错误。当codeNone 时,如果字段有任何错误它都将返回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字段。

使用Forminitial参数可以实现。该参数是字段名到初始值的一个字典。只需要包含你期望给出初始值的字段;不需要包含表单中的所有字段。例如:

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

这些值只显示在没有绑定的表单中,即使没有提供特定值它们也不会作为后备的值。

注意,如果字段有定义initial, _而_实例化表单时也提供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" /></td></tr><tr><th>Url:</th><td><input type="url" name="url" /></td></tr><tr><th>Comment:</th><td><input type="text" name="comment" /></td></tr>

检查表单数据是否改变

Form.`has_changed`()

当你需要检查表单的数据是否从初始数据发生改变时,可以使用表单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 中的不同,has_changed() 将为True,否则为False。 计算的结果是通过调用表单每个字段的Field.has_changed() 得到的。

从表单中访问字段

Form.`fields`

你可以从表单实例的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>

可你可以修改表单实例的字段来改变字段在表单中的表示:

>>> f.as_table().split('\n')[0]'<tr><th>Name:</th><td><input name="name" type="text" value="instance" /></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" /></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" /></td></tr>'

访问“清洁”的数据

Form.`cleaned_data`

表单类中的每个字段不仅负责验证数据,还负责“清洁”它们 —— 将它们转换为正确的格式。这是个非常好用的功能,因为它允许字段以多种方式输入数据,并总能得到一致的输出。

例如,DateField 将输入转换为Python 的 datetime.date 对象。无论你传递的是'1994-07-15' 格式的字符串、datetime.date 对象、还是其它格式的数字,DateField 将始终将它们转换成datetime.date 对象,只要它们是合法的。

一旦你创建一个表单实例并通过验证后,你就可以通过它的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 —— 始终将输入转换为Unicode 字符串。我们将在这篇文档的后面将是编码的影响。

如果你的数据_没有_ 通过验证,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 始终_只_ 包含表单中定义的字段,即使你在构建表单 时传递了额外的数据。在下面的例子中,我们传递一组额外的字段给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'}

表单合法时,cleaned_data 将包含_所有_字段的键和值,即使传递的数据不包含某些可选字段的值。在下面的例子中,传递的数据字典不包含nick_name 字段的值,但是cleaned_data 任然包含它,只是值为空:

>>> from django.forms import Form>>> class OptionalPersonForm(Form):...     first_name = CharField()...     last_name = CharField()...     nick_name = 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_datanick_name 设置为一个空字符串,这是因为nick_nameCharFieldCharField 将空值作为一个空字符串。每个字段都知道自己的“空”值 —— 例如,DateField 的空值是None 而不是一个空字符串。关于每个字段空值的完整细节,参见“内建的Field 类”一节中每个字段的“空值”提示。

你可以自己编写代码来对特定的字段(根据它们的名字)或者表单整体(考虑到不同字段的组合)进行验证。更多信息参见_表单和字段验证_。

输出表单为HTML

表单对象的第二个任务是将它渲染成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" /></td></tr><tr><th><label for="id_message">Message:</label></th><td><input type="text" name="message" id="id_message" /></td></tr><tr><th><label for="id_sender">Sender:</label></th><td><input type="email" name="sender" id="id_sender" /></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" /></td></tr><tr><th><label for="id_message">Message:</label></th><td><input type="text" name="message" id="id_message" value="Hi there" /></td></tr><tr><th><label for="id_sender">Sender:</label></th><td><input type="email" name="sender" id="id_sender" value="foo@example.com" /></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>。注意事项:

虽然print 表单时<table> 是默认的输出格式,但是还有其它格式可用。每个格式对应于表单对象的一个方法,每个方法都返回一个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" /></p>\n<p><label for="id_message">Message:</label> <input type="text" name="message" id="id_message" /></p>\n<p><label for="id_sender">Sender:</label> <input type="text" name="sender" id="id_sender" /></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" /></p><p><label for="id_message">Message:</label> <input type="text" name="message" id="id_message" /></p><p><label for="id_sender">Sender:</label> <input type="email" name="sender" id="id_sender" /></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> 标签包含一个字段。它_不_包含<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" /></li>\n<li><label for="id_message">Message:</label> <input type="text" name="message" id="id_message" /></li>\n<li><label for="id_sender">Sender:</label> <input type="email" name="sender" id="id_sender" /></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" /></li><li><label for="id_message">Message:</label> <input type="text" name="message" id="id_message" /></li><li><label for="id_sender">Sender:</label> <input type="email" name="sender" id="id_sender" /></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" /></td></tr>\n<tr><th><label for="id_message">Message:</label></th><td><input type="text" name="message" id="id_message" /></td></tr>\n<tr><th><label for="id_sender">Sender:</label></th><td><input type="email" name="sender" id="id_sender" /></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.as_table())<tr><th><label for="id_subject">Subject:</label></th><td><input id="id_subject" type="text" name="subject" maxlength="100" /></td></tr><tr><th><label for="id_message">Message:</label></th><td><input type="text" name="message" id="id_message" /></td></tr><tr><th><label for="id_sender">Sender:</label></th><td><input type="email" name="sender" id="id_sender" /></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`

将必填的表单行和有错误的表单行定义不同的样式特别常见。例如,你想将必填的表单行以粗体显示、将错误以红色显示。

表单类具有一对钩子,可以使用它们来添加class 属性给必填的行或有错误的行:只需简单地设置Form.error_css_class 和/或 Form.required_css_class 属性:

from django.forms import Formclass ContactForm(Form):    error_css_class = 'error'    required_css_class = 'required'    # ... and the rest of your fields here

一旦你设置好,将根据需要设置行的"error" 和/或"required" CSS 类型。 其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>

Changed in Django 1.8:

required_css_class 添加到<label> 标签,如上面所看到的。

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

Form.`auto_id`

默认情况下,表单的渲染方法包含:

id 属性值通过在表单字段名称的前面加上id_ 生成。但是如果你想改变id 的生成方式或者完全删除 HTML id 属性和<label>标签,这个行为是可配置的。

id 和label 的行为使用表单构造函数的auto_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" /></td></tr><tr><th>Message:</th><td><input type="text" name="message" /></td></tr><tr><th>Sender:</th><td><input type="email" name="sender" /></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" /></li><li>Message: <input type="text" name="message" /></li><li>Sender: <input type="email" name="sender" /></li><li>Cc myself: <input type="checkbox" name="cc_myself" /></li>>>> print(f.as_p())<p>Subject: <input type="text" name="subject" maxlength="100" /></p><p>Message: <input type="text" name="message" /></p><p>Sender: <input type="email" name="sender" /></p><p>Cc myself: <input type="checkbox" name="cc_myself" /></p>

如果auto_id 设置为True,那么输出的表示_将_ 包含<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" /></td></tr><tr><th><label for="message">Message:</label></th><td><input type="text" name="message" id="message" /></td></tr><tr><th><label for="sender">Sender:</label></th><td><input type="email" name="sender" id="sender" /></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" /></li><li><label for="message">Message:</label> <input type="text" name="message" id="message" /></li><li><label for="sender">Sender:</label> <input type="email" name="sender" id="sender" /></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" /></p><p><label for="message">Message:</label> <input type="text" name="message" id="message" /></p><p><label for="sender">Sender:</label> <input type="email" name="sender" id="sender" /></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" /></td></tr><tr><th><label for="id_for_message">Message:</label></th><td><input type="text" name="message" id="id_for_message" /></td></tr><tr><th><label for="id_for_sender">Sender:</label></th><td><input type="email" name="sender" id="id_for_sender" /></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" /></li><li><label for="id_for_message">Message:</label> <input type="text" name="message" id="id_for_message" /></li><li><label for="id_for_sender">Sender:</label> <input type="email" name="sender" id="id_for_sender" /></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" /></p><p><label for="id_for_message">Message:</label> <input type="text" name="message" id="id_for_message" /></p><p><label for="id_for_sender">Sender:</label> <input type="email" name="sender" id="id_for_sender" /></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 名称的后面。

使用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" /></li><li><label for="id_for_message">Message</label> <input type="text" name="message" id="id_for_message" /></li><li><label for="id_for_sender">Sender</label> <input type="email" name="sender" id="id_for_sender" /></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" /></li><li><label for="id_for_message">Message -></label> <input type="text" name="message" id="id_for_message" /></li><li><label for="id_for_sender">Sender -></label> <input type="email" name="sender" id="id_for_sender" /></li><li><label for="id_for_cc_myself">Cc myself -></label> <input type="checkbox" name="cc_myself" id="id_for_cc_myself" /></li>

注意,该标签后缀只有当label 的最后一个字符不是表单符号(., !, ?:)时才添加。

New in Django 1.8\.

字段可以定义自己的label_suffix。而且将优先于Form.label_suffix。在运行时刻,后缀可以使用label_tag()label_suffix 参数覆盖。

字段的顺序

as_p()as_ul()as_table() 中,字段以表单类中定义的顺序显示。例如,在ContactForm 示例中,字段定义的顺序为subject, message, sender, cc_myself。若要重新排序HTML 中的输出,只需改变字段在类中列出的顺序。

错误如何显示

如果你渲染一个绑定的表单对象,渲染时将自动运行表单的验证,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" /></td></tr><tr><th>Message:</th><td><input type="text" name="message" value="Hi there" /></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" /></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" /></li><li>Message: <input type="text" name="message" value="Hi there" /></li><li><ul class="errorlist"><li>Enter a valid email address.</li></ul>Sender: <input type="email" name="sender" value="invalid email address" /></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" /></p><p>Message: <input type="text" name="message" value="Hi there" /></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" /></p><p>Cc myself: <input checked="checked" type="checkbox" name="cc_myself" /></p>

自定义错误清单的格式

默认情况下,表单使用django.forms.utils.ErrorList 来格式化验证时的错误。如果你希望使用另外一种类来显示错误,可以在构造时传递(在Python 2 中将 __str__ 替换为__unicode__):

>>> 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" /></p><p>Message: <input type="text" name="message" value="Hi there" /></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" /></p><p>Cc myself: <input checked="checked" type="checkbox" name="cc_myself" /></p>

Changed in Django 1.7:

django.forms.util 重命名为django.forms.utils

更细粒度的输出

as_p()as_ul()as_table() 方法是为懒惰的程序员准备的简单快捷方法 —— 它们不是显示表单的唯一方式。

_class _BoundField

用于显示HTML 表单或者访问表单实例的一个属性。

__str__()(Python 2 上为__unicode__)方法显示该字段的HTML。

以字段的名称为键,用字典查询语法查询表单,可以获取一个 BoundField

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

迭代表单可以获取所有的BoundField

>>> form = ContactForm()>>> for boundfield in form: print(boundfield)<input id="id_subject" type="text" name="subject" maxlength="100" /><input type="text" name="message" id="id_message" /><input type="email" name="sender" id="id_sender" /><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" />>>> f = ContactForm(auto_id='id_%s')>>> print(f['message'])<input type="text" name="message" id="id_message" />

若要获取字段的错误列表,可以访问字段的errors 属性。

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" />>>> 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.`label_tag`(_contents=None_, _attrs=None_, _label_suffix=None_)

可以调用label_tag 方法单独渲染表单字段的label 标签:

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

如果你提供一个可选的contents 参数,它将替换自动生成的label 标签。另外一个可选的attrs ?参数可以包含<label> 标签额外的属性。

生成的HTML 包含表单的label_suffix(默认为一个冒号),或者当前字段的label_suffix。可选的label_suffix 参数允许你覆盖之前设置的后缀。例如,你可以使用一个空字符串来隐藏已选择字段的label。如果在模板中需要这样做,你可以编写一个自定义的过滤器来允许传递参数给label_tag

Changed in Django 1.8:

如果可用,label 将包含required_css_class

BoundField.`css_classes`()

当你使用Django 的快捷的渲染方法时,习惯使用CSS ?类型来表示必填的表单字段和有错误的字段。如果你是手工渲染一个表单,你可以使用css_classes 方法访问这些CSS 类型:

>>> f = ContactForm(data)>>> f['message'].css_classes()'required'

除了错误和必填的类型之外,如果你还想提供额外的类型,你可以用参数传递它们:

>>> f = ContactForm(data)>>> f['message'].css_classes('foo bar')'foo bar required'

BoundField.`value`()

这个方法用于渲染字段的原始值,与用Widget 渲染的值相同:

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

BoundField.`id_for_label`

使用这个属性渲染字段的ID。例如,如果你在模板中手工构造一个<label>(尽管 label_tag() 将为你这么做):

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

默认情况下,它是在字段名称的前面加上id_ (上面的例子中将是“id_my_field”)。你可以通过设置字段Widget 的attrs 来修改ID。例如,像这样声明一个字段:

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

使用上面的模板,将渲染成:

<label for="myFIELD">...</label><input id="myFIELD" type="text" name="my_field" />

绑定上传的文件到表单

处理带有FileFieldImageField 字段的表单比普通的表单要稍微复杂一点。

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

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

其次,当你使用表单时,你需要绑定文件数据。文件数据的处理与普通的表单数据是分开的,所以如果表单包含FileFieldImageField,绑定表单时你需要指定第二个参数。所以,如果我们扩展ContactForm 并包含一个名为mugshotImageField,我们需要绑定包含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)

构造一个未绑定的表单和往常一样 —— 将表单数据_和_文件数据同时省略:

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

测试multipart 表单

Form.`is_multipart`()

如果你正在编写可重用的视图或模板,你可能事先不知道你的表单是否是一个multipart 表单。is_multipart() 方法告诉你表单提交时是否要求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>

子类化表单

如果你有多个表单类共享相同的字段,你可以使用子类化来减少冗余。

当你子类化一个自定义的表单类时,生成的子类将包含父类中的所有字段,以及在子类中定义的字段。

在下面的例子中,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" /></li><li>Message: <input type="text" name="message" /></li><li>Sender: <input type="email" name="sender" /></li><li>Cc myself: <input type="checkbox" name="cc_myself" /></li><li>Priority: <input type="text" name="priority" /></li>

可以子类化多个表单,将表单作为“mix-ins”。在下面的例子中,BeatleForm 子类化PersonFormInstrumentForm ,所以它的字段列表包含两个父类的所有字段:

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

New in Django 1.7\.

表单前缀

Form.`prefix`

你可以将几个Django 表单放在一个<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" /></li><li><label for="id_mother-last_name">Last name:</label> <input type="text" name="mother-last_name" id="id_mother-last_name" /></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" /></li><li><label for="id_father-last_name">Last name:</label> <input type="text" name="father-last_name" id="id_father-last_name" /></li>

译者:Django 文档协作翻译小组,原文:Form API。

本文以 CC BY-NC-SA 3.0 协议发布,转载请保留作者署名和文章出处。

Django 文档协作翻译小组人手紧缺,有兴趣的朋友可以加入我们,完全公益性质。交流群:467338606。

网友最爱