Forms API

关于这个文件

本文档涵盖了Django表单API的细节。 您应该先阅读introduction to working with forms

绑定和非绑定表单

A Form instance is either bound to a set of data, or unbound.

  • 如果绑定到一组数据,则它能够验证该数据,并将表单呈现为HTML,并显示HTML中显示的数据。
  • 如果它是未绑定的,它不能进行验证(因为没有数据可以验证!),但它仍然可以将空白表单呈现为HTML。
Form[source]

要创建一个未绑定的Form实例,只需实例化该类:

>>> f = ContactForm()

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

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

在这个字典中,键是字段名称,对应于Form类中的属性。 这些值是您要验证的数据。 这些通常是字符串,但不要求它们是字符串;您传递的数据类型取决于Field,我们稍后会看到。

形成。 is_bound T0> ¶ T1>

如果您需要在运行时区分绑定和未绑定表单实例,请检查表单的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实例,就应该把它的数据看成是不可变的,无论它是否有数据。

使用表单来验证数据

形成。清洁 T0>()¶ T1>

如果必须为相互依赖的字段添加自定义验证,请在Form上实施clean()方法。 请参阅Cleaning and validating fields that depend on each other

形成。 is_valid T0>()¶ T1>

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
形成。错误 T0> ¶ T1>

访问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 T0>()¶ T1>

返回一个将字段映射到其原始ValidationError实例的dict

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

无论何时您需要通过code标识错误,都可以使用此方法。 这样可以在出现给定的错误时重写错误消息或在视图中写入自定义逻辑。 It can also be used to serialize the errors in a custom format (e.g. XML); for instance, as_json() relies on as_data().

as_data()方法的需求是由于向后兼容性。 之前ValidationError实例一旦将呈现错误消息添加到Form.errors字典中,就会丢失。 Ideally Form.errors would have stored ValidationError instances and methods with an as_ prefix could render them, but it had to be done the other way around in order not to break code that expects rendered error messages in Form.errors.

Form.errors。 as_json T0>( escape_html =假 T1>)¶ T2>

返回序列化为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 T0>( escape_html =假 T1>)¶ T2>
Django 2.0新增功能

以适合序列化为JSON的字典形式返回错误。 Form.errors.as_json()返回序列化的JSON,这会在序列化之前返回错误数据。

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

形成。add_error字段错误

此方法允许从Form.clean()方法内或从表单外部的特定字段中添加错误;例如从一个视图。

field参数是应将错误添加到的字段的名称。 如果它的值是None,则错误将被视为由Form.non_field_errors()返回的非字段错误。

error参数可以是一个简单的字符串,或者最好是ValidationError的一个实例。 定义表单错误时,请参阅Raising ValidationError以获得最佳做法。

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

形成。has_errorfieldcode = None

此方法返回一个布尔值,指定某个字段是否存在具有特定错误code的错误。 如果codeNone,如果该字段包含任何错误,它将返回True

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

形成。 non_field_errors T0>()¶ T1>

此方法返回Form.errors中与特定字段无关的错误列表。 This includes ValidationErrors that are raised in Form.clean() and errors added using Form.add_error(None, "...").

未绑定表单的行为

验证没有数据的表单是没有意义的,但为了记录,以下是未绑定表单的情况:

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

动态初始值

形成。初始 T0> ¶ T1>

使用initial在运行时声明表单字段的初始值。 例如,您可能需要使用当前会话的用户名填写username字段。

要做到这一点,请使用initial参数到Form 这个参数,如果给出,应该是一个字典映射字段名称到初始值。 只包含您指定初始值的字段;没有必要在表单中包含每个字段。 例如:

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

这些值仅针对未绑定表单显示,如果未提供特定值,则不会将其用作备用值。

如果Field定义initial ,那么在实例化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>
形成。get_initial_for_fieldfieldfield_name
Django 1.11新增功能

使用get_initial_for_field()检索表单字段的初始数据。 它从Form.initialField.initial中依次检索数据,并评估任何可调用的初始值。

检查哪些表单数据已经改变

形成。 has_changed T0>()¶ T1>

当需要检查表单数据是否已经从初始数据改变时,在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()

has_changed() will be True if the data from request.POST differs from what was provided in initial or False otherwise. 通过为表单中的每个字段调用Field.has_changed()来计算结果。

形成。 changed_data T0> ¶ T1>

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

的形式访问字段

形成。字段 T0> ¶ T1>

您可以从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>'

访问“干净的”数据

形成。 cleaned_data T0> ¶ T1>

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

例如,DateField将输入标准化为一个Python datetime.date对象。 Regardless of whether you pass it a string in the format '1994-07-15', a datetime.date object, or a number of other formats, DateField will always normalize it to a datetime.date object as long as it’s valid.

一旦用一组数据创建了一个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)总是将输入清理为字符串。 我们将在本文稍后介绍编码的含义。

如果您的数据不验证,则cleaned_data字典仅包含有效字段:

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

cleaned_data will always only contain a key for fields defined in the Form, even if you pass extra data when you define the Form. 在这个例子中,我们将一些额外的字段传递给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'}

When the Form is valid, cleaned_data will include a key and value for all its fields, even if the data didn’t include a value for some optional fields. 在此示例中,数据字典不包含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'}

In this above example, the cleaned_data value for nick_name is set to an empty string, because nick_name is CharField, and CharFields treat empty values as an empty string. 每个字段类型都知道它的“空白”值是什么 - 例如,对于DateField,它是None而不是空字符串。 有关每个字段在此情况下的行为的详细信息,请参阅下面“内置Field类”部分中每个字段的“空值”注释。

您可以编写代码来执行特定表单字段(基于其名称)或表单整体(考虑各种字段的组合)的验证。 有关这方面的更多信息,请参见Form and field validation

将表格输出为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输出将适当地包含该数据。 例如,如果一个字段由&lt; input type =“text”&gt;表示,则数据将在value属性。 如果一个字段由&lt; input type =“checkbox”&gt;表示,那么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>
在Django 1.11中更改:

已将checked属性更改为使用HTML5布尔语法,而不是checked="checked"

这个默认输出是一个两列的HTML表格,每个字段都有一个<tr> 注意以下几点:

  • For flexibility, the output does not include the <table> and </table> tags, nor does it include the <form> and </form> tags or an <input type="submit"> tag. 这是你的工作。
  • 每个字段类型都有一个默认的HTML表示。 CharField is represented by an <input type="text"> and EmailField by an <input type="email">. BooleanField is represented by an <input type="checkbox">. 注意这些仅仅是合理的默认值;您可以使用小部件来指定给定字段使用哪个HTML,我们稍后会解释它。
  • 每个标签的HTML name是直接从ContactForm类中的属性名称取得的。
  • 每个字段的文本标签 - 例如'Subject:''Message:''cc 我自己:'是通过将所有下划线转换为空格和上方第一个字母来从字段名称生成的。 再说一次,注意这些只是明智的违约;您也可以手动指定标签。
  • 每个文本标签都包含在HTML <label>标签中,该标签通过id指向适当的表单字段。 它的id依次是通过将'id_'添加到字段名称中生成的。 输出中默认包含id属性和<label>标记,以遵循最佳做法,但您可以更改该行为。
  • 输出使用HTML5语法,目标为&lt;!DOCTYPE html&gt; 例如,它使用布尔属性,如checked,而不是checked='checked'的XHTML样式。

虽然<table>输出是print表单时的默认输出样式,但其他输出样式可用。 每种样式都可作为表单对象的方法使用,每种呈现方法都会返回一个字符串。

as_p()

形成。 as_p T0>()¶ T1>

as_p() renders the form as a series of <p> tags, with each <p> containing one field:

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

形成。 as_ul T0>()¶ T1>

as_ul() renders the form as a series of <li> tags, with each <li> containing one field. It does not include the <ul> or </ul>, so that you can specify any HTML attributes on the <ul> for flexibility:

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

形成。 as_table T0>()¶ T1>

Finally, as_table() outputs the form as an HTML <table>. 这与print完全相同。 In fact, when you print a form object, it calls its as_table() method behind the scenes:

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

造型需要或错误的形式行

形成。 error_css_class T0> ¶ T1>
形成。 required_css_class T0> ¶ T1>

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

The Form class has a couple of hooks you can use to add class attributes to required rows or to rows with errors: simply set the Form.error_css_class and/or Form.required_css_class attributes:

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>标签

形成。 auto_id T0> ¶ T1>

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

  • 表单元素上的HTML id属性。
  • 相应的标签周围的<label>标签。 HTML <label>标记指定哪个标签文本与哪个表单元素相关联。 这种小小的增强使得表单更易于使用,辅助设备更易于使用。 使用<label>标签总是一个好主意。

id属性值是通过将id_前置到表单字段名称中生成的。 但是,如果您想要完全更改id约定或移除HTML id属性和<label>标签,则此行为是可配置的。

Form构造函数使用auto_id参数来控制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,那么表单输出将包含<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>

If auto_id is set to any other true value – such as a string that doesn’t include %s – then the library will act as if auto_id is True.

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

形成。 label_suffix T0> ¶ T1>

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

可以使用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_tag()label_suffix参数覆盖。

形成。 use_required_attribute T0> ¶ T1>

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

Formsets instantiate forms with use_required_attribute=False to avoid incorrect browser validation when adding and deleting forms from a formset.

配置窗体小部件的渲染

形成。 default_renderer T0> ¶ T1>
Django 1.11新增功能

指定用于表单的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()快捷键中,字段按照您在表格课堂。 For example, in the ContactForm example, the fields are defined in the order subject, message, sender, cc_myself. 要重新排序HTML输出,只需更改这些字段在类中列出的顺序即可。

还有其他几种自定义顺序的方法:

形成。 field_order T0> ¶ T1>

默认Form.field_order=None,它保留了您在表单类中定义字段的顺序。 如果field_order是字段名称的列表,字段按列表的顺序排序,剩余的字段按默认顺序附加。 列表中的未知字段名称将被忽略。 这使得可以通过将其设置为None来禁用子类中的字段而不必重新定义排序。

您也可以使用FormForm.field_order参数来覆盖字段顺序。 如果一个Form定义field_order ,则在实例化Form时包含field_order后者field_order将具有优先权。

形成。 order_fields T0>( field_order T1>)¶ T2>

您可以使用order_fields()field_order中的字段名称列表重新排列字段。

如何显示错误

如果渲染一个绑定的Form对象,渲染动作会自动运行表单的验证,如果尚未发生,HTML输出将包含验证错误,如&lt; ul class =“errorlist”&gt;附近的字段。 错误消息的具体位置取决于您使用的输出方法:

>>> 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()方法只是捷径 - 它们不是表单对象的唯一方法被显示。

BoundField[source]

用于显示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

绑定列。 auto_id T0> ¶ T1>

这个BoundField的HTML ID属性。 如果Form.auto_idFalse,则返回空字符串。

绑定列。数据 T0> ¶ T1>

This property returns the data for this BoundField extracted by the widget’s value_from_datadict() method, or None if it wasn’t given:

>>> unbound_form = ContactForm()
>>> print(unbound_form['subject'].data)
None
>>> bound_form = ContactForm(data={'subject': 'My Subject'})
>>> print(bound_form['subject'].data)
My Subject
绑定列。错误 T0> ¶ T1>

A list-like object that is displayed as an HTML <ul class="errorlist"> when printed:

>>> 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)
''
绑定列。字段 T0> ¶ T1>

这个BoundField包装的表单类的形式Field实例。

绑定列。形式 T0> ¶ T1>

这个BoundFieldForm实例绑定到了。

绑定列。 help_text T0> ¶ T1>

该字段的help_text

绑定列。 html_name T0> ¶ T1>

将在小部件的HTML name属性中使用的名称。 它考虑了prefix的形式。

绑定列。 id_for_label T0> ¶ T1>

使用此属性来呈现此字段的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 />
绑定列。 is_hidden T0> ¶ T1>

如果BoundField的小部件被隐藏,则返回True

绑定列。标签 T0> ¶ T1>

字段的label 这用在label_tag()中。

绑定列。名称 T0> ¶ T1>

该字段的名称格式为:

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

BoundField

绑定列。as_hiddenattrs = None** kwargs[source]

返回一个HTML字符串,将其表示为&lt; input type =“hidden”&gt;

**kwargs传递给as_widget()

这种方法主要用于内部。 你应该使用一个小部件。

绑定列。as_widget(widget=None, attrs=None, only_initial=False)[source]

通过渲染传递的小部件来呈现字段,添加以attrs形式传递的任何HTML属性。 如果没有指定小部件,则将使用该字段的默认小部件。

only_initial is used by Django internals and should not be set explicitly.

绑定列。css_classes()[source]

当您使用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'
绑定列。label_tag(contents=None, attrs=None, label_suffix=None)[source]

要单独呈现表单字段的标签标签,可以调用它的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

绑定列。value()[source]

使用此方法呈现此字段的原始值,因为它将由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()

领域。get_bound_fieldformfield_name[source]

接受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时,绑定表单时需要指定第二个参数。 因此,如果我们扩展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()

测试多部分表单

形成。 is_multipart T0>()¶ T1>

如果您正在编写可重用的视图或模板,您可能不会提前知道您的表单是否为多部分表单。 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。 In this example, BeatleForm subclasses both PersonForm and InstrumentForm (in that order), and its field list includes the fields from the parent classes:

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

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

形式的前缀

形成。前缀 T0> ¶ T1>

你可以在一个<form>标签中放入几个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" 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'