关于此文档
本文件涵盖了Django表格API的详细信息。你应该读一下 introduction to working with forms 第一。
A 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
,稍后我们将看到。
如果需要在运行时区分绑定和未绑定的表单实例,请检查表单的 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
实例已经创建,您应该认为它的数据是不可变的,不管它是否有数据。
实施一 clean()
你的方法 Form
当必须为相互依赖的字段添加自定义验证时。见 清理和验证相互依赖的字段 例如用法。
的主要任务是 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
访问 errors
属性以获取错误消息词典:
>>> f.errors
{'sender': ['Enter a valid email address.'], 'subject': ['This field is required.']}
在本字典中,键是字段名,值是表示错误消息的字符串列表。错误消息存储在列表中,因为一个字段可以有多个错误消息。
您可以访问 errors
不用调用 is_valid()
第一。表单的数据将在您第一次调用 is_valid()
或访问 errors
.
验证例程将只被调用一次,不管您访问了多少次 errors
或调用 is_valid()
. 这意味着如果验证有副作用,那么这些副作用只会触发一次。
返回A dict
将字段映射到原始字段 ValidationError
实例。
>>> f.errors.as_data()
{'sender': [ValidationError(['Enter a valid email address.'])],
'subject': [ValidationError(['This field is required.'])]}
在需要通过它来识别错误的任何时候都可以使用此方法 code
. 这样可以在出现给定错误时重写错误消息或在视图中写入自定义逻辑。它还可以用于以自定义格式(例如XML)序列化错误;例如, as_json()
依赖于 as_data()
.
需要的是 as_data()
方法是由于向后兼容性。以前 ValidationError
一旦他们 提供 错误消息已添加到 Form.errors
字典。理想的 Form.errors
本来可以储存的 ValidationError
实例和方法 as_
前缀可以呈现它们,但它必须以另一种方式执行,以避免破坏期望在中呈现错误消息的代码。 Form.errors
.
返回序列化为JSON的错误。
>>> f.errors.as_json()
{"sender": [{"message": "Enter a valid email address.", "code": "invalid"}],
"subject": [{"message": "This field is required.", "code": "required"}]}
默认情况下, as_json()
不会逃脱其输出。如果您使用它来处理像对表单视图的AJax请求(客户端解释响应并将错误插入页面中)这样的事情,则您需要确保在客户端逃避结果,以避免跨站点脚本攻击的可能性。您可以在JavaScript中通过以下方式完成此操作: element.textContent = errorText
或使用jQuery $(el).text(errorText)
(而不是它的 .html()
功能)。
如果出于某种原因不想使用客户端转义,也可以设置 escape_html=True
错误消息将被转义,以便您可以直接在HTML中使用它们。
将错误作为适合序列化到JSON的字典返回。 Form.errors.as_json()
返回序列化的JSON,而返回序列化前的错误数据。
这个 escape_html
参数的行为如中所述 Form.errors.as_json()
.
此方法允许从中向特定字段添加错误 Form.clean()
方法,或者完全从窗体外部;例如从视图。
这个 field
参数是应向其添加错误的字段的名称。如果它的价值是 None
错误将被视为返回的非字段错误 Form.non_field_errors()
.
这个 error
参数可以是字符串,或者最好是 ValidationError
。看见 饲养 ValidationError 定义表格错误时的最佳实践。
注意 Form.add_error()
自动从中删除相关字段 cleaned_data
.
此方法返回一个布尔值,指定字段是否有特定错误 code
.如果 code
是 None
,它会回来的 True
如果字段包含任何错误。
要检查非字段错误,请使用 NON_FIELD_ERRORS
作为 field
参数。
此方法返回错误列表 Form.errors
与特定字段无关。这包括 ValidationError
在…中长大的 Form.clean()
和使用添加的错误 Form.add_error(None, "...")
.
验证没有数据的表单是没有意义的,但需要注意的是,以下是未绑定表单的情况:
>>> f = ContactForm()
>>> f.is_valid()
False
>>> f.errors
{}
使用 initial
在运行时声明窗体字段的初始值。例如,您可能希望填写 username
具有当前会话用户名的字段。
要完成此操作,请使用 initial
参数设置为 Form
。此参数(如果给定)应该是将字段名映射到初始值的字典。只包含要为其指定初始值的字段;没有必要在表单中包含所有字段。例如:
>>> f = ContactForm(initial={"subject": "Hi there!"})
这些值仅对未绑定的表单显示,如果未提供特定值,则不会用作回退值。
If a Field
defines initial
and you
include initial
when instantiating the Form
, then the latter
initial
will have precedence. In this example, initial
is provided both
at the field level and at the form instance level, and the latter gets
precedence:
>>> from django import forms
>>> class CommentForm(forms.Form):
... name = forms.CharField(initial="class")
... url = forms.URLField()
... comment = forms.CharField()
...
>>> f = CommentForm(initial={"name": "instance"}, auto_id=False)
>>> print(f)
<div>Name:<input type="text" name="name" value="instance" required></div>
<div>Url:<input type="url" name="url" required></div>
<div>Comment:<input type="text" name="comment" required></div>
返回表单域的初始数据。它从以下位置检索数据 Form.initial
如果存在,则尝试 Field.initial
。评估可调用值。
建议使用 BoundField.initial
完毕 get_initial_for_field()
因为 BoundField.initial
具有更简单的界面。此外,不同于 get_initial_for_field()
, BoundField.initial
缓存其值。这在处理返回值可以更改的可计算函数时尤其有用(例如 datetime.now
或 uuid.uuid4
):
>>> import uuid
>>> class UUIDCommentForm(CommentForm):
... identifier = forms.UUIDField(initial=uuid.uuid4)
...
>>> f = UUIDCommentForm()
>>> f.get_initial_for_field(f.fields["identifier"], "identifier")
UUID('972ca9e4-7bfe-4f5b-af7d-07b3aa306334')
>>> f.get_initial_for_field(f.fields["identifier"], "identifier")
UUID('1b411fab-844e-4dec-bd4f-e9b0495f04d0')
>>> # Using BoundField.initial, for comparison
>>> f["identifier"].initial
UUID('28a09c59-5f00-4ed9-9179-a3b074fa9c30')
>>> f["identifier"].initial
UUID('28a09c59-5f00-4ed9-9179-a3b074fa9c30')
使用 has_changed()
你的方法 Form
当需要检查表单数据是否已从初始数据更改时。
>>> data = {
... "subject": "hello",
... "message": "Hi there",
... "sender": "foo@example.com",
... "cc_myself": True,
... }
>>> f = ContactForm(data, initial=data)
>>> f.has_changed()
False
提交表格时,我们重新构建表格并提供原始数据,以便进行比较:
>>> f = ContactForm(request.POST, initial=data)
>>> f.has_changed()
has_changed()
将 True
如果数据来自 request.POST
与中提供的不同 initial
或 False
否则。结果是通过调用 Field.has_changed()
对于表单中的每个字段。
这个 changed_data
属性返回其值在窗体绑定数据(通常为 request.POST
)与中提供的不同 initial
. 如果没有数据不同,则返回空列表。
>>> f = ContactForm(request.POST, initial=data)
>>> if f.has_changed():
... print("The following fields changed: %s" % ", ".join(f.changed_data))
...
>>> f.changed_data
['subject', 'message']
您可以访问的字段 Form
实例从ITS fields
属性:
>>> for row in f.fields.values():
... print(row)
...
<django.forms.fields.CharField object at 0x7ffaac632510>
<django.forms.fields.URLField object at 0x7ffaac632f90>
<django.forms.fields.CharField object at 0x7ffaac3aa050>
>>> f.fields["name"]
<django.forms.fields.CharField object at 0x7ffaac6324d0>
您可以更改该字段并 BoundField
的 Form
实例以更改其在表单中的呈现方式:
>>> f.as_div().split("</div>")[0]
'<div><label for="id_subject">Subject:</label><input type="text" name="subject" maxlength="100" required id="id_subject">'
>>> f["subject"].label = "Topic"
>>> f.as_div().split("</div>")[0]
'<div><label for="id_subject">Topic:</label><input type="text" name="subject" maxlength="100" required id="id_subject">'
注意不要更改 base_fields
属性,因为此修改将影响所有后续 ContactForm
同一个Python进程中的实例:
>>> f.base_fields["subject"].label_suffix = "?"
>>> another_f = CommentForm(auto_id=False)
>>> f.as_div().split("</div>")[0]
'<div><label for="id_subject">Subject?</label><input type="text" name="subject" maxlength="100" required id="id_subject">'
A中的每个字段 Form
类不仅负责验证数据,还负责“清理”数据——将其规范化为一致的格式。这是一个很好的特性,因为它允许以多种方式输入特定字段的数据,从而始终产生一致的输出。
例如, DateField
将输入规范化为python datetime.date
对象。不管是否以格式传递字符串 '1994-07-15'
,A datetime.date
对象或许多其他格式, DateField
总是将其规范化为 datetime.date
对象,只要它有效。
一旦您创建了 Form
实例具有一组数据并对其进行验证,则可以通过其 cleaned_data
属性:
>>> data = {
... "subject": "hello",
... "message": "Hi there",
... "sender": "foo@example.com",
... "cc_myself": True,
... }
>>> f = ContactForm(data)
>>> f.is_valid()
True
>>> f.cleaned_data
{'cc_myself': True, 'message': 'Hi there', 'sender': 'foo@example.com', 'subject': 'hello'}
注意,任何基于文本的字段——例如 CharField
或 EmailField
--总是将输入清理为字符串。我们稍后将在本文中介绍编码含义。
如果您的数据有 not 验证、 cleaned_data
字典仅包含有效字段:
>>> data = {
... "subject": "",
... "message": "Hi there",
... "sender": "invalid email address",
... "cc_myself": True,
... }
>>> f = ContactForm(data)
>>> f.is_valid()
False
>>> f.cleaned_data
{'cc_myself': True, 'message': 'Hi there'}
cleaned_data
will always only contain a key for fields defined in the
Form
, even if you pass extra data when you define the Form
. In this
example, we pass a bunch of extra fields to the ContactForm
constructor,
but cleaned_data
contains only the form's fields:
>>> data = {
... "subject": "hello",
... "message": "Hi there",
... "sender": "foo@example.com",
... "cc_myself": True,
... "extra_field_1": "foo",
... "extra_field_2": "bar",
... "extra_field_3": "baz",
... }
>>> f = ContactForm(data)
>>> f.is_valid()
True
>>> f.cleaned_data # Doesn't contain extra_field_1, etc.
{'cc_myself': True, 'message': 'Hi there', 'sender': 'foo@example.com', 'subject': 'hello'}
当 Form
是有效的, cleaned_data
将包括的键和值 all 它的字段,即使数据不包括某些可选字段的值。在此示例中,数据字典不包括 nick_name
字段,但是 cleaned_data
包括它,并且值为空值:
>>> from django import forms
>>> class OptionalPersonForm(forms.Form):
... first_name = forms.CharField()
... last_name = forms.CharField()
... nick_name = forms.CharField(required=False)
...
>>> data = {"first_name": "John", "last_name": "Lennon"}
>>> f = OptionalPersonForm(data)
>>> f.is_valid()
True
>>> f.cleaned_data
{'nick_name': '', 'first_name': 'John', 'last_name': 'Lennon'}
在上面的示例中, cleaned_data
价值观 nick_name
设置为空字符串,因为 nick_name
是 CharField
和 CharField
s将空值视为空字符串。每个字段类型都知道其“空白”值是什么——例如,对于 DateField
它是 None
而不是空字符串。有关本例中每个字段行为的完整详细信息,请参见“内置”中每个字段的“空值”注释。 Field
“类”部分。
您可以编写代码来对特定表单域(基于其名称)或整个表单(考虑各种域的组合)执行验证。有关此的详细信息位于 表单和字段验证 .
的第二个任务 Form
对象的目的是将其自身呈现为HTML。要做到这一点, print
IT:
>>> f = ContactForm()
>>> print(f)
<div><label for="id_subject">Subject:</label><input type="text" name="subject" maxlength="100" required id="id_subject"></div>
<div><label for="id_message">Message:</label><input type="text" name="message" required id="id_message"></div>
<div><label for="id_sender">Sender:</label><input type="email" name="sender" required id="id_sender"></div>
<div><label for="id_cc_myself">Cc myself:</label><input type="checkbox" name="cc_myself" id="id_cc_myself"></div>
如果表单绑定到数据,则HTML输出将相应地包括该数据。例如,如果一个字段由 <input type="text">
,数据将位于 value
属性。如果一个字段由 <input type="checkbox">
,则该HTML将包括 checked
如果适用,请执行以下操作:
>>> data = {
... "subject": "hello",
... "message": "Hi there",
... "sender": "foo@example.com",
... "cc_myself": True,
... }
>>> f = ContactForm(data)
>>> print(f)
<div><label for="id_subject">Subject:</label><input type="text" name="subject" value="hello" maxlength="100" required id="id_subject"></div>
<div><label for="id_message">Message:</label><input type="text" name="message" value="Hi there" required id="id_message"></div>
<div><label for="id_sender">Sender:</label><input type="email" name="sender" value="foo@example.com" required id="id_sender"></div>
<div><label for="id_cc_myself">Cc myself:</label><input type="checkbox" name="cc_myself" id="id_cc_myself" checked></div>
此默认输出会将每个字段换成 <div>
。请注意以下事项:
为了灵活起见,输出会 not 包括 <form>
和 </form>
标记或一个 <input type="submit">
标签。你的工作就是这么做。
每个字段类型都有默认的HTML表示形式。 CharField
由具有 <input type="text">
和 EmailField
由 <input type="email">
。 BooleanField(null=False)
由具有 <input type="checkbox">
.请注意,这些只是合理的默认值;您可以通过使用小部件指定字段使用哪个HTML,我们将很快解释这一点。
HTML name
对于每个标记,直接从其在 ContactForm
类。
每个字段的文本标签——例如 'Subject:'
, 'Message:'
和 'Cc myself:'
通过将所有下划线转换为空格并将第一个字母大写,从字段名生成。同样,请注意,这些只是合理的默认值;您也可以手动指定标签。
每个文本标签都被一个HTML包围 <label>
标记,该标记通过其 id
. 它的 id
反过来,是通过提前 'id_'
字段名。这个 id
属性和 <label>
默认情况下,标记包含在输出中,以遵循最佳实践,但您可以更改该行为。
输出使用HTML5语法,目标 <!DOCTYPE html>
. 例如,它使用布尔属性,例如 checked
而不是XHTML风格的 checked='checked'
.
虽然 <div>
输出是在以下情况下的默认输出样式 print
表单您可以使用自己的表单模板来自定义输出,该模板可以在站点范围内、按表单或按实例进行设置。看见 可重用表单模板 。
在执行以下操作时的默认渲染 print
表单使用以下方法和属性。
template_name
¶将表单转换为字符串时呈现的模板的名称,例如Via print(form)
或在模板中通过 {{ form }}
。
默认情况下,返回呈现器的 form_template_name
。您可以将其设置为字符串模板名称,以便覆盖特定表单类的名称。
render()
¶Render方法由调用 __str__
以及 Form.as_div()
, Form.as_table()
, Form.as_p()
,以及 Form.as_ul()
方法:研究方法。所有参数都是可选的,默认为:
template_name
: Form.template_name
context
: Value returned by Form.get_context()
renderer
: Value returned by Form.default_renderer
通过路过 template_name
您可以自定义仅用于单个呼叫的模板。
get_context()
¶返回用于呈现表单的模板上下文。
可用的上下文为:
form
:装订的表格。
fields
:除隐藏字段外的所有绑定字段。
hidden_fields
:所有隐藏的绑定字段。
errors
:所有与字段无关或与隐藏字段相关的表单错误。
template_name_label
¶用于呈现字段的 <label>
,在调用 BoundField.label_tag()
/legend_tag()
。可以通过覆盖此属性或更一般地通过覆盖默认模板来更改每个表单,另请参阅 覆盖内置表单模板 。
更改表单输出样式的建议方法是设置站点范围、每个表单或每个实例的自定义表单模板。看见 可重用表单模板 举个例子。
提供以下帮助器函数是为了实现向后兼容性,它们是 Form.render()
传递一个特定的 template_name
价值。
备注
对于框架提供的模板和输出样式,默认 as_div()
是推荐的 as_p()
, as_table()
,以及 as_ul()
版本作为模板实现 <fieldset>
和 <legend>
对相关输入进行分组,屏幕阅读器用户可以更轻松地导航。
每个帮助器将一个表单方法与一个属性配对,该属性提供适当的模板名称。
as_div()
¶使用的模板 as_div()
。默认: 'django/forms/div.html'
。
as_div()
将该窗体呈现为一系列 <div>
元素,每个元素 <div>
包含一个字段,例如:
>>> f = ContactForm()
>>> f.as_div()
…提供类似于以下内容的HTML:
<div>
<label for="id_subject">Subject:</label>
<input type="text" name="subject" maxlength="100" required id="id_subject">
</div>
<div>
<label for="id_message">Message:</label>
<input type="text" name="message" required id="id_message">
</div>
<div>
<label for="id_sender">Sender:</label>
<input type="email" name="sender" required id="id_sender">
</div>
<div>
<label for="id_cc_myself">Cc myself:</label>
<input type="checkbox" name="cc_myself" id="id_cc_myself">
</div>
as_p()
¶使用的模板 as_p()
。默认: 'django/forms/p.html'
。
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()
¶使用的模板 as_ul()
。默认: 'django/forms/ul.html'
。
as_ul()
将该窗体呈现为一系列 <li>
标记,每个标记 <li>
包含一个字段的。是的 not 包括 <ul>
或 </ul>
,以便您可以在 <ul>
为提高灵活性:
>>> f = ContactForm()
>>> f.as_ul()
'<li><label for="id_subject">Subject:</label> <input id="id_subject" type="text" name="subject" maxlength="100" required></li>\n<li><label for="id_message">Message:</label> <input type="text" name="message" id="id_message" required></li>\n<li><label for="id_sender">Sender:</label> <input type="email" name="sender" id="id_sender" required></li>\n<li><label for="id_cc_myself">Cc myself:</label> <input type="checkbox" name="cc_myself" id="id_cc_myself"></li>'
>>> print(f.as_ul())
<li><label for="id_subject">Subject:</label> <input id="id_subject" type="text" name="subject" maxlength="100" required></li>
<li><label for="id_message">Message:</label> <input type="text" name="message" id="id_message" required></li>
<li><label for="id_sender">Sender:</label> <input type="email" name="sender" id="id_sender" required></li>
<li><label for="id_cc_myself">Cc myself:</label> <input type="checkbox" name="cc_myself" id="id_cc_myself"></li>
as_table()
¶使用的模板 as_table()
。默认: 'django/forms/table.html'
。
as_table()
将表单呈现为HTML <table>
:
>>> f = ContactForm()
>>> f.as_table()
'<tr><th><label for="id_subject">Subject:</label></th><td><input id="id_subject" type="text" name="subject" maxlength="100" required></td></tr>\n<tr><th><label for="id_message">Message:</label></th><td><input type="text" name="message" id="id_message" required></td></tr>\n<tr><th><label for="id_sender">Sender:</label></th><td><input type="email" name="sender" id="id_sender" required></td></tr>\n<tr><th><label for="id_cc_myself">Cc myself:</label></th><td><input type="checkbox" name="cc_myself" id="id_cc_myself"></td></tr>'
>>> print(f)
<tr><th><label for="id_subject">Subject:</label></th><td><input id="id_subject" type="text" name="subject" maxlength="100" required></td></tr>
<tr><th><label for="id_message">Message:</label></th><td><input type="text" name="message" id="id_message" required></td></tr>
<tr><th><label for="id_sender">Sender:</label></th><td><input type="email" name="sender" id="id_sender" required></td></tr>
<tr><th><label for="id_cc_myself">Cc myself:</label></th><td><input type="checkbox" name="cc_myself" id="id_cc_myself"></td></tr>
对需要或有错误的表单行和字段设置样式是很常见的。例如,您可能希望以粗体显示所需的表单行,并以红色突出显示错误。
这个 Form
类有几个挂钩,您可以用来添加 class
所需行或有错误行的属性:设置 Form.error_css_class
和/或 Form.required_css_class
属性::
from django import forms
class ContactForm(forms.Form):
error_css_class = "error"
required_css_class = "required"
# ... and the rest of your fields here
一旦您这样做了,将给出行 "error"
和/或 "required"
类,视需要而定。该HTML将如下所示:
>>> f = ContactForm(data)
>>> print(f)
<div class="required"><label for="id_subject" class="required">Subject:</label> ...
<div class="required"><label for="id_message" class="required">Message:</label> ...
<div class="required"><label for="id_sender" class="required">Sender:</label> ...
<div><label for="id_cc_myself">Cc myself:</label> ...
>>> f["subject"].label_tag()
<label class="required" for="id_subject">Subject:</label>
>>> f["subject"].legend_tag()
<legend class="required" for="id_subject">Subject:</legend>
>>> f["subject"].label_tag(attrs={"class": "foo"})
<label for="id_subject" class="foo required">Subject:</label>
>>> f["subject"].legend_tag(attrs={"class": "foo"})
<legend for="id_subject" class="foo required">Subject:</legend>
指定 renderer 用于窗体。默认为 None
这意味着使用 FORM_RENDERER
设置。
在声明窗体或使用 renderer
参数 Form.__init__()
. 例如::
from django import forms
class MyForm(forms.Form):
default_renderer = MyRenderer()
或:
form = MyForm(renderer=MyRenderer())
在 as_p()
, as_ul()
和 as_table()
快捷方式时,字段将按照您在表单类中定义它们的顺序显示。比如在 ContactForm
例如,字段按顺序定义 subject
, message
, sender
, cc_myself
.要重新排序HTML输出,请更改这些字段在类中的列出顺序。
定制订单还有其他几种方法:
默认情况下 Form.field_order=None
,它保留您在窗体类中定义字段的顺序。如果 field_order
是字段名列表,字段按列表指定的顺序排列,其余字段按默认顺序追加。忽略列表中的未知字段名。这样就可以通过将子类中的字段设置为 None
不用重新定义顺序。
您也可以使用 Form.field_order
对A的论证 Form
覆盖字段顺序。如果A Form
定义 field_order
and 你包括 field_order
当实例化 Form
,然后是后者 field_order
将具有优先权。
您可以随时使用 order_fields()
字段名列表如中所示 field_order
.
如果您呈现一个边界 Form
对象时,呈现操作将自动运行窗体的验证(如果尚未进行验证),并且HTML输出将把验证错误作为 <ul class="errorlist">
在田野附近。错误消息的特定位置取决于您使用的输出方法:
>>> data = {
... "subject": "",
... "message": "Hi there",
... "sender": "invalid email address",
... "cc_myself": True,
... }
>>> f = ContactForm(data, auto_id=False)
>>> print(f)
<div>Subject:
<ul class="errorlist"><li>This field is required.</li></ul>
<input type="text" name="subject" maxlength="100" required aria-invalid="true">
</div>
<div>Message:
<textarea name="message" cols="40" rows="10" required>Hi there</textarea>
</div>
<div>Sender:
<ul class="errorlist"><li>Enter a valid email address.</li></ul>
<input type="email" name="sender" value="invalid email address" required aria-invalid="true">
</div>
<div>Cc myself:
<input type="checkbox" name="cc_myself" checked>
</div>
默认情况下,表单使用 django.forms.utils.ErrorList
若要格式化验证错误,请执行以下操作。 ErrorList
是一个类似列表的对象,其中 initlist
是错误列表。此外,该类还具有以下属性和方法。
呈现错误列表时要使用的css类。任何提供的类都会添加到默认的 errorlist
班级。
指定 renderer 用于以下用途 ErrorList
。默认为 None
这意味着使用由 FORM_RENDERER
布景。
调用时使用的模板的名称 __str__
或 render()
。默认情况下,这是 'django/forms/errors/list/default.html'
的代理,它是 'ul.html'
模板。
调用时使用的模板的名称 as_text()
。默认情况下,这是 'django/forms/errors/list/text.html'
。此模板以项目符号列表的形式呈现错误。
调用时使用的模板的名称 as_ul()
。默认情况下,这是 'django/forms/errors/list/ul.html'
。此模板在 <li>
带有换行的标签 <ul>
使用由定义的CSS类 error_class
。
Render方法由调用 __str__
以及由 as_ul()
方法。
所有参数都是可选的,默认为:
template_name
: Value returned by template_name
context
: Value returned by get_context()
renderer
: Value returned by renderer
使用定义的模板呈现错误列表 template_name_text
。
使用定义的模板呈现错误列表 template_name_ul
。
如果您想要自定义错误的呈现,可以通过重写 template_name
属性,或者更一般地通过重写默认模板,另请参见 覆盖内置表单模板 。
这个 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">
特定于字段的输出遵循Form对象的 auto_id
设置:
>>> f = ContactForm(auto_id=False)
>>> print(f["message"])
<input type="text" name="message" required>
>>> f = ContactForm(auto_id="id_%s")
>>> print(f["message"])
<input type="text" name="message" id="id_message" required>
BoundField
¶此的html id属性 BoundField
. 返回空字符串,如果 Form.auto_id
是 False
.
此属性返回此 BoundField
由小部件的 value_from_datadict()
方法,或 None
如果它没有被给予:
>>> unbound_form = ContactForm()
>>> print(unbound_form["subject"].data)
None
>>> bound_form = ContactForm(data={"subject": "My Subject"})
>>> print(bound_form["subject"].data)
My Subject
A list-like object 它显示为一个HTML <ul class="errorlist">
打印时:
>>> data = {"subject": "hi", "message": "", "sender": "", "cc_myself": ""}
>>> f = ContactForm(data, auto_id=False)
>>> print(f["message"])
<input type="text" name="message" required aria-invalid="true">
>>> f["message"].errors
['This field is required.']
>>> print(f["message"].errors)
<ul class="errorlist"><li>This field is required.</li></ul>
>>> f["subject"].errors
[]
>>> print(f["subject"].errors)
>>> str(f["subject"].errors)
''
在呈现有错误的字段时, aria-invalid="true"
将在字段的窗口小部件上设置,以向屏幕阅读器用户指示存在错误。
形式 Field
来自窗体类的实例 BoundField
包裹。
这个 Form
实例如下 BoundField
是必然的。
使用此属性可呈现此字段的ID。例如,如果要手动构造一个 <label>
在您的模板中(尽管 label_tag()
/legend_tag()
将为您做到这一点):
<label for="{{ form.my_field.id_for_label }}">...</label>{{ my_field }}
默认情况下,这将是字段名的前缀为 id_
(上面的示例为“id_my_field`
”)。您可以通过设置来修改ID attrs
在字段的小部件上。例如,声明这样的字段:
my_field = forms.CharField(widget=forms.TextInput(attrs={"id": "myFIELD"}))
使用上面的模板,将呈现如下内容:
<label for="myFIELD">...</label><input id="myFIELD" type="text" name="my_field" required>
使用 BoundField.initial
若要检索表单域的初始数据,请执行以下操作。它从以下位置检索数据 Form.initial
如果存在,则尝试 Field.initial
。评估可调用值。看见 初始表单值 了解更多的例子。
BoundField.initial
缓存其返回值,这在处理返回值可能更改的可计算对象时尤其有用(例如 datetime.now
或 uuid.uuid4
):
>>> from datetime import datetime
>>> class DatedCommentForm(CommentForm):
... created = forms.DateTimeField(initial=datetime.now)
...
>>> f = DatedCommentForm()
>>> f["created"].initial
datetime.datetime(2021, 7, 27, 9, 5, 54)
>>> f["created"].initial
datetime.datetime(2021, 7, 27, 9, 5, 54)
vbl.使用 BoundField.initial
是推荐使用的 get_initial_for_field()
。
返回 True
如果这样 BoundField
的小部件被隐藏。
这个 label
of the field. This is used in label_tag()
/legend_tag()
。
表单中此字段的名称:
>>> f = ContactForm()
>>> print(f["subject"].name)
subject
>>> print(f["message"].name)
message
使用呈现的模板的名称 BoundField.as_field_group()
。
属性,该属性返回 template_name
如果设置为其他值 field_template_name
。
BoundField
¶使用以下命令呈现该字段 BoundField.render()
具有缺省值,从而呈现 BoundField
,包括其标签、帮助文本和使用模板的 template_name
如果设置为其他值 field_template_name
返回一个HTML字符串,用于将其表示为 <input type="hidden">
.
**kwargs
被传递给 as_widget()
.
这种方法主要在内部使用。您应该改为使用小部件。
通过呈现传递的小部件来呈现字段,添加作为 attrs
. 如果没有指定小部件,那么将使用字段的默认小部件。
only_initial
由Django内部使用,不应显式设置。
当您使用Django的呈现快捷键时,将使用CSS类来指示必需的表单域或包含错误的域。如果要手动呈现窗体,则可以使用 css_classes
方法:
>>> f = ContactForm(data={"message": ""})
>>> f["message"].css_classes()
'required'
如果除了可能需要的错误和必需类之外,您还想提供一些其他类,则可以将这些类作为参数提供:
>>> f = ContactForm(data={"message": ""})
>>> f["message"].css_classes("foo bar")
'foo bar required'
使用由指定的模板呈现表单域的标签标记 Form.template_name_label
。
可用的上下文为:
field
:此实例为 BoundField
。
contents
:默认情况下,连接的字符串为 BoundField.label
和 Form.label_suffix
(或 Field.label_suffix
,如果已设置)。这可以由 contents
和 label_suffix
争论。
attrs
:A dict
含 for
, Form.required_css_class
,以及 id
。 id
由字段的微件生成 attrs
或 BoundField.auto_id
。其他属性可以由 attrs
争论。
use_tag
:布尔值,它是 True
如果标签有一个 id
。如果 False
默认模板省略了 tag
。
tag
:用于自定义标记的可选字符串,默认为 label
。
小技巧
在您的模板中 field
是对象的实例 BoundField
。因此 field.field
访问 BoundField.field
作为您声明的字段,例如 forms.CharField
。
若要单独呈现表单域的标签标记,可以调用其 label_tag()
方法:
>>> f = ContactForm(data={"message": ""})
>>> print(f["message"].label_tag())
<label for="id_message">Message:</label>
如果想要自定义呈现,可以通过重写 Form.template_name_label
属性,或者更一般地通过重写默认模板,另请参见 覆盖内置表单模板 。
打电话 label_tag()
使用 tag='legend'
用来呈现标签的步骤 <legend>
标签。这在呈现单选和多个复选框小部件时非常有用 <legend>
可能比 <label>
。
Render方法由调用 as_field_group
。所有参数都是可选的,默认为:
template_name
: BoundField.template_name
context
: Value returned by BoundField.get_context()
renderer
: Value returned by Form.default_renderer
通过路过 template_name
您可以自定义仅用于单个呼叫的模板。
使用此方法呈现该字段的原始值,就像它将由 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()
:
以…为例 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
AS "multipart/form-data"
:
<form enctype="multipart/form-data" method="post" action="/foo/">
其次,在使用表单时,需要绑定文件数据。文件数据与普通表单数据分开处理,因此当您的表单包含 FileField
和 ImageField
,则在绑定窗体时需要指定第二个参数。因此,如果我们将ContactForm扩展为包含一个 ImageField
被呼叫 mugshot
,我们需要绑定包含大头照图片的文件数据:
# Bound form with an image field
>>> from django.core.files.uploadedfile import SimpleUploadedFile
>>> data = {
... "subject": "hello",
... "message": "Hi there",
... "sender": "foo@example.com",
... "cc_myself": True,
... }
>>> file_data = {"mugshot": SimpleUploadedFile("face.jpg", b"file data")}
>>> f = ContactFormWithMugshot(data, file_data)
实际上,您通常会指定 request.FILES
作为文件数据的源(就像使用 request.POST
作为表单数据的来源):
# Bound form with an image field, data from the request
>>> f = ContactFormWithMugshot(request.POST, request.FILES)
构造未绑定的表单与以往一样--省略两个表单数据 and 文件数据:
# Unbound form with an image field
>>> f = ContactFormWithMugshot()
如果您正在编写可重用的视图或模板,您可能无法提前知道您的表单是否为多部分表单。这个 is_multipart()
方法告诉您表单是否需要多部分编码才能提交:
>>> f = ContactFormWithMugshot()
>>> f.is_multipart()
True
下面是一个如何在模板中使用它的示例:
{% if form.is_multipart %}
<form enctype="multipart/form-data" method="post" action="/foo/">
{% else %}
<form method="post" action="/foo/">
{% endif %}
{{ form }}
</form>
如果你有多个 Form
类共享字段,您可以使用子类来消除冗余。
当您将自定义 Form
类,生成的子类将包括父类的所有字段,然后是子类中定义的字段。
在本例中, ContactFormWithPriority
包含来自的所有字段 ContactForm
,外加一个额外的字段, priority
。这个 ContactForm
首先对字段进行排序:
>>> class ContactFormWithPriority(ContactForm):
... priority = forms.CharField()
...
>>> f = ContactFormWithPriority(auto_id=False)
>>> print(f)
<div>Subject:<input type="text" name="subject" maxlength="100" required></div>
<div>Message:<textarea name="message" cols="40" rows="10" required></textarea></div>
<div>Sender:<input type="email" name="sender" required></div>
<div>Cc myself:<input type="checkbox" name="cc_myself"></div>
<div>Priority:<input type="text" name="priority" required></div>
可以细分多个Form,将Form视为混合。在本例中, BeatleForm
子类和子类 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)
<div>First name:<input type="text" name="first_name" required></div>
<div>Last name:<input type="text" name="last_name" required></div>
<div>Instrument:<input type="text" name="instrument" required></div>
<div>Haircut type:<input type="text" name="haircut_type" required></div>
可以声明性地移除 Field
通过将字段名称设置为从父类继承 None
在子类上。例如:
>>> from django import forms
>>> class ParentForm(forms.Form):
... name = forms.CharField()
... age = forms.IntegerField()
...
>>> class ChildForm(ParentForm):
... name = None
...
>>> list(ChildForm().fields)
['age']
您可以将几个Django表单放在一个表单中 <form>
标签。给每个人 Form
它自己的命名空间,请使用 prefix
关键字参数:
>>> mother = PersonForm(prefix="mother")
>>> father = PersonForm(prefix="father")
>>> print(mother)
<div><label for="id_mother-first_name">First name:</label><input type="text" name="mother-first_name" required id="id_mother-first_name"></div>
<div><label for="id_mother-last_name">Last name:</label><input type="text" name="mother-last_name" required id="id_mother-last_name"></div>
>>> print(father)
<div><label for="id_father-first_name">First name:</label><input type="text" name="father-first_name" required id="id_father-first_name"></div>
<div><label for="id_father-last_name">Last name:</label><input type="text" name="father-last_name" required id="id_father-last_name"></div>
前缀也可以在Form类上指定:
>>> class PersonForm(forms.Form):
... ...
... prefix = "person"
...
7月 22, 2024