创建一个表单类时,最重要的部分是定义表单的字段。每个字段都可以有自定义的验证逻辑,以及一些其它的钩子。
虽然字段类主要使用在表单类中,但你也可以直接实例化它们来使用,以便更好地了解它们是如何工作的。每个字段实例都有一个clean()方法, 它接受一个参数,然后返回“清洁的”数据或者抛出一个django.forms.ValidationError异常:
>>> from django import forms
>>> f = forms.EmailField()
>>> f.clean('[email protected]')
'[email protected]'
>>> f.clean('invalid email address')
Traceback (most recent call last):
...
ValidationError: ['Enter a valid email address.']
每个字段类的构造函数至少接受这些参数。有些字段类接受额外的、字段特有的参数,但以下参数应该总是能接受:
默认情况下,每个字段 类都假设必需有值,所以如果你传递一个空的值 —— 不管是None 还是空字符串("") —— clean() 将引发一个ValidationError 异常:
>>> from django import forms
>>> f = forms.CharField()
>>> f.clean('foo')
'foo'
>>> f.clean('')
Traceback (most recent call last):
...
ValidationError: ['This field is required.']
>>> f.clean(None)
Traceback (most recent call last):
...
ValidationError: ['This field is required.']
>>> f.clean(' ')
' '
>>> f.clean(0)
'0'
>>> f.clean(True)
'True'
>>> f.clean(False)
'False'
若要表示一个字段不是必需的,请传递required=False 给字段的构造函数:
>>> f = forms.CharField(required=False)
>>> f.clean('foo')
'foo'
>>> f.clean('')
''
>>> f.clean(None)
''
>>> f.clean(0)
'0'
>>> f.clean(True)
'True'
>>> f.clean(False)
'False'
如果字段 具有required=False,而你传递给clean() 一个空值,clean() 将返回一个转换后的空值而不是引发ValidationError。例如CharField,它将是一个空的Unicode 字符串。对于其它字段类,它可能是None。(每个字段各不相同)。
label 参数让你指定字段“对人类友好”的label。当字段在表单中显示时将用到它。
正如在前面“输出表单为HTML”中解释的,字段默认label 是通过将字段名中所有的下划线转换成空格并大写第一个字母生成的。如果默认的标签不合适,可以指定label。
下面是一个完整示例,表单为它的两个字段实现了label。我们指定auto_id=False来让输出简单一些:
>>> from django import forms
>>> class CommentForm(forms.Form):
... name = forms.CharField(label='Your name')
... url = forms.URLField(label='Your Web site', required=False)
... comment = forms.CharField()
>>> f = CommentForm(auto_id=False)
>>> print(f)
<tr><th>Your name:</th><td><input type="text" name="name" /></td></tr>
<tr><th>Your Web site:</th><td><input type="url" name="url" /></td></tr>
<tr><th>Comment:</th><td><input type="text" name="comment" /></td></tr>
label_suffix 参数让你基于每个字段覆盖表单的label_suffix:
>>> class ContactForm(forms.Form):
... age = forms.IntegerField()
... nationality = forms.CharField()
... captcha_answer = forms.IntegerField(label='2 + 2', label_suffix=' =')
>>> f = ContactForm(label_suffix='?')
>>> print(f.as_p())
<p><label for="id_age">Age?</label> <input id="id_age" name="age" type="number" /></p>
<p><label for="id_nationality">Nationality?</label> <input id="id_nationality" name="nationality" type="text" /></p>
<p><label for="id_captcha_answer">2 + 2 =</label> <input id="id_captcha_answer" name="captcha_answer" type="number" /></p>
initial 参数让你指定渲染未绑定的表单中的字段时使用的初始值。
若要指定动态的初始数据,参见Form.initial 参数。
这个参数的使用场景是当你想要显示一个“空”的表单,其某个字段初始化为一个特定的值。例如:
>>> from django import forms
>>> class CommentForm(forms.Form):
... name = forms.CharField(initial='Your name')
... url = forms.URLField(initial='http://')
... comment = forms.CharField()
>>> f = CommentForm(auto_id=False)
>>> print(f)
<tr><th>Name:</th><td><input type="text" name="name" value="Your name" /></td></tr>
<tr><th>Url:</th><td><input type="url" name="url" value="http://" /></td></tr>
<tr><th>Comment:</th><td><input type="text" name="comment" /></td></tr>
你可能正在想为什么不在显示表单的时候传递一个包含初始化值的字典?如果这么做,你将触发验证过程,此时HTML 输出将包含任何验证中产生的错误:
>>> class CommentForm(forms.Form):
... name = forms.CharField()
... url = forms.URLField()
... comment = forms.CharField()
>>> default_data = {'name': 'Your name', 'url': 'http://'}
>>> f = CommentForm(default_data, auto_id=False)
>>> print(f)
<tr><th>Name:</th><td><input type="text" name="name" value="Your name" /></td></tr>
<tr><th>Url:</th><td><ul class="errorlist"><li>Enter a valid URL.</li></ul><input type="url" name="url" value="http://" /></td></tr>
<tr><th>Comment:</th><td><ul class="errorlist"><li>This field is required.</li></ul><input type="text" name="comment" /></td></tr>
这就是为什么initial 的值只在未绑定的表单中显示的原因。对于绑定的表单,HTML 输出将使用绑定的数据。
还要注意,如果某个字段的值没有给出,initial 值不会作为“后备”的数据。initial 值只用于原始表单的显示:
>>> class CommentForm(forms.Form):
... name = forms.CharField(initial='Your name')
... url = forms.URLField(initial='http://')
... comment = forms.CharField()
>>> data = {'name': '', 'url': '', 'comment': 'Foo'}
>>> f = CommentForm(data)
>>> f.is_valid()
False
# The form does *not* fall back to using the initial values.
>>> f.errors
{'url': ['This field is required.'], 'name': ['This field is required.']}
除了常数之外,你还可以传递一个可调用的对象:
>>> import datetime
>>> class DateForm(forms.Form):
... day = forms.DateField(initial=datetime.date.today)
>>> print(DateForm())
<tr><th>Day:</th><td><input type="text" name="day" value="12/23/2008" /><td></tr>
可调用对象在未绑定的表单显示的时候才计算,不是在定义的时候。
help_text 参数让你指定字段的描述文本。如果提供help_text,在通过表单的便捷方法(例如,as_ul())渲染字段时,它将紧接着字段显示。
下面是一个完整的示例,表单为它的两个字段实现了help_text。 我们指定auto_id=False来让输出简单一些:
>>> from django import forms
>>> class HelpTextContactForm(forms.Form):
... subject = forms.CharField(max_length=100, help_text='100 characters max.')
... message = forms.CharField()
... sender = forms.EmailField(help_text='A valid email address, please.')
... cc_myself = forms.BooleanField(required=False)
>>> f = HelpTextContactForm(auto_id=False)
>>> print(f.as_table())
<tr><th>Subject:</th><td><input type="text" name="subject" maxlength="100" /><br /><span class="helptext">100 characters max.</span></td></tr>
<tr><th>Message:</th><td><input type="text" name="message" /></td></tr>
<tr><th>Sender:</th><td><input type="email" name="sender" /><br />A valid email address, please.</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" /> <span class="helptext">100 characters max.</span></li>
<li>Message: <input type="text" name="message" /></li>
<li>Sender: <input type="email" name="sender" /> A valid email address, please.</li>
<li>Cc myself: <input type="checkbox" name="cc_myself" /></li>
>>> print(f.as_p())
<p>Subject: <input type="text" name="subject" maxlength="100" /> <span class="helptext">100 characters max.</span></p>
<p>Message: <input type="text" name="message" /></p>
<p>Sender: <input type="email" name="sender" /> A valid email address, please.</p>
<p>Cc myself: <input type="checkbox" name="cc_myself" /></p>
error_messages 参数让你覆盖字段引发的异常中的默认信息。传递的是一个字典,其键为你想覆盖的错误信息。例如,下面是默认的错误信息:
>>> from django import forms
>>> generic = forms.CharField()
>>> generic.clean('')
Traceback (most recent call last):
...
ValidationError: ['This field is required.']
而下面是自定义的错误信息:
>>> name = forms.CharField(error_messages={'required': 'Please enter your name'})
>>> name.clean('')
Traceback (most recent call last):
...
ValidationError: ['Please enter your name']
在下面的内建的字段一节中,每个字段都定义了它自己的错误信息。
重命名_has_changed() 为该方法。
has_changed() 方法用于决定字段的值是否从初始值发生了改变。返回True 或False。
更多信息,参见Form.has_changed()。
自然,表单的库会带有一系列表示常见需求的字段。 这一节记录每个内建字段。
对于每个字段,我们描述默认的widget。我们还会指出提供空值时的返回值(参见上文的required 以理解它的含义)。
注
因为所有的Field 子类都默认带有required=True,这里的验证条件很重要。如果你希望表单中包含一个既可以为True 也可以为False 的布尔值(例如,复选框可以勾上也可以不勾上),你必须要记住在创建BooleanField时传递required=False。
invalid_choice 错误消息可能包含%(value)s,它将被选择的选项替换掉。
接收一个额外的必选参数:
用来作为该字段选项的一个二元组组成的可迭代对象(例如,列表或元组)或者一个可调用对象。参数的格式与模型字段的choices 参数相同。更多细节参见模型字段参考中关于选项的文档。如果参数是可调用的,它在字段的表单初始化时求值。
添加传递一个可调用对象给choices 的功能。
与ChoiceField 很像,只是TypedChoiceField 接受两个额外的参数coerce 和empty_value。
接收的额外参数:
接收一个参数并返回强制转换后的值的一个函数。例如内建的int、float、bool 和其它类型。默认为id 函数。注意强制转换在输入验证结束后发生,所以它可能强制转换不在 choices 中的值。
用于表示“空”的值。默认为空字符串;None 是另外一个常见的选项。注意这个值不会被coerce 参数中指定的函数强制转换,所以请根据情况进行选择。
接收一个可选的参数:
一个格式的列表,用于转换一个字符串为datetime.date 对象。
如果没有提供input_formats,默认的输入格式为:
['%Y-%m-%d', # '2006-10-25'
'%m/%d/%Y', # '10/25/2006'
'%m/%d/%y'] # '10/25/06'
另外,如果你在设置中指定USE_L10N=False,以下的格式也将包含在默认的输入格式中:
['%b %d %Y', # 'Oct 25 2006'
'%b %d, %Y', # 'Oct 25, 2006'
'%d %b %Y', # '25 Oct 2006'
'%d %b, %Y', # '25 Oct, 2006'
'%B %d %Y', # 'October 25 2006'
'%B %d, %Y', # 'October 25, 2006'
'%d %B %Y', # '25 October 2006'
'%d %B, %Y'] # '25 October, 2006'
另见本地化格式。
接收一个可选的参数:
一个格式的列表,用于转换一个字符串为datetime.datetime 对象。
如果没有提供input_formats,默认的输入格式为:
['%Y-%m-%d %H:%M:%S', # '2006-10-25 14:30:59'
'%Y-%m-%d %H:%M', # '2006-10-25 14:30'
'%Y-%m-%d', # '2006-10-25'
'%m/%d/%Y %H:%M:%S', # '10/25/2006 14:30:59'
'%m/%d/%Y %H:%M', # '10/25/2006 14:30'
'%m/%d/%Y', # '10/25/2006'
'%m/%d/%y %H:%M:%S', # '10/25/06 14:30:59'
'%m/%d/%y %H:%M', # '10/25/06 14:30'
'%m/%d/%y'] # '10/25/06'
另见本地化格式。
自1.7版起已弃用:DateTimeField 与SplitDateTimeWidget 一起使用的功能被废弃并将在Django 1.9 中删除。请改用SplitDateTimeField。
max_value 和min_value 错误信息可能包含%(limit_value)s,它们将被真正的限制值替换。类似地,max_digits、max_decimal_places 和 max_whole_digits 错误消息可能包含%(max)s。
接收四个可选的参数:
它们控制字段中允许的值的范围,应该以decimal.Decimal 值给出。
值允许的最大位数(小数点之前和之后的数字总共的位数,前导的零将被删除)。
允许的最大小数位。
接收任何可以被parse_duration() 理解的格式。
具有两个可选的参数用于验证,max_length 和min_length。如果提供,这两个参数确保字符串的最大和最小长度。
具有两个可选的参数用于验证,max_length 和 allow_empty_file。如果提供,这两个参数确保文件名的最大长度,而且即使文件内容为空时验证也会成功。
若要了解UploadedFile 对象的更多内容,参见文件上传的文档。
当你在表单中使用FileField 时,必须要记住绑定文件数据到表单上。
max_length 错误信息表示文件名的长度。在错误信息中,%(max)d 将替换为文件的最大长度,%(length)d 将替换为当前文件名的长度。
这个字段允许从一个特定的目录选择文件。它接受三个额外的参数;只有path 是必需的:
你想要列出的目录的绝对路径。这个目录必须存在。
如果为False(默认值),只用直接位于path 下的文件或目录作为选项。如果为True,将递归访问这个目录,其所有的子目录和文件都将作为选项。
正则表达式表示的一个模式;只有匹配这个表达式的名称才允许作为选项。
可选。为True 或False。默认为True。表示是否应该包含指定位置的文件。它和allow_folders 必须有一个为True。
可选。为True 或False。 默认为False。表示是否应该包含指定位置的目录。 它和allow_files 必须有一个为True。
接收两个可选的参数用于验证,max_value 和min_value。它们控制字段中允许的值的范围。
使用ImageField需要安装Pillow并支持您使用的图像格式。如果在上传图片时遇到损坏 图像错误,通常意味着Pillow不了解其格式。要解决这个问题,请安装相应的库并重新安装Pillow。
在表单上使用ImageField时,您还必须记住bind the file data to the form。
在字段清理和验证后,UploadedFile对象将有一个额外的image属性,包含Pillow 图像实例,用于检查文件是一个有效的图像。UploadedFile.content_type也会更新为由Pillow确定的图片内容类型。
max_value和min_value错误消息可能包含%(limit_value)s,将替换为适当的限制。
采用两个可选参数进行验证:
它们控制字段中允许的值的范围。
自1.7版起已弃用:此字段已弃用,支持GenericIPAddressField。
包含IPv4或IPv6地址的字段。
IPv6地址规范化遵循 RFC 4291部分2.2,包括使用该部分第3段中建议的IPv4格式,如::ffff:192.0.2.0例如,2001:0::0:01将被标准化为2001::1和::ffff:0a0a:0a0a ::ffff:10.10.10.10。所有字符都转换为小写。
有两个可选参数:
限制指定协议的有效输入。接受的值为both(默认值),IPv4或IPv6。匹配不区分大小写。
解开IPv4映射地址,例如::ffff:192.0.2.1。如果启用此选项,则该地址将解包到192.0.2.1。默认为禁用。只能在protocol设置为'both'时使用。
invalid_choice错误消息可能包含%(value)s,将替换为所选择的选项。
对于ChoiceField,需要一个额外的必需参数choices。
就像MultipleChoiceField,除了TypedMultipleChoiceField需要两个额外的参数,coerce和empty_value。
invalid_choice错误消息可能包含%(value)s,将替换为所选择的选项。
对于TypedChoiceField,需要两个额外的参数coerce和empty_value。
需要一个必需的参数:
指定为字符串或编译的正则表达式对象的正则表达式。
也采用max_length和min_length,它们的作用与CharField相同。
自1.8版起已弃用:可接受的参数error_message也被接受用于向后兼容性,但会在Django 2.0中删除。提供错误消息的首选方法是使用error_messages参数,传递具有'invalid'的字典作为键,并将错误消息作为值。
需要一个额外的必需参数:
应用于验证字段值的字段列表(按提供它们的顺序)。
>>> from django.forms import ComboField
>>> f = ComboField(fields=[CharField(max_length=20), EmailField()])
>>> f.clean('[email protected]')
'[email protected]'
>>> f.clean('[email protected]')
Traceback (most recent call last):
...
ValidationError: ['Ensure this value has at most 20 characters (it has 28).']
聚合共同产生单个值的多个字段的逻辑。
此字段是抽象的,必须是子类。与单值字段相反,MultiValueField的子类不能实现clean(),而是实现compress()。
需要一个额外的必需参数:
字段的元组,其值被清除并随后组合成单个值。每个字段的值由字段中的相应字段清除 - 第一个值由第一个字段清除,第二个值由第二个字段清除等。清除所有字段后,通过compress()将干净值列表合并为一个值。
还需要一个额外的可选参数:
默认为True,在这种情况下,如果没有为任何字段提供值,则会出现required验证错误。
设置为False时,可以将Field.required属性设置为False,以使其为可选字段。如果没有为必填字段提供值,则会出现不完整验证错误。
可以在MultiValueField子类上定义默认不完整错误消息,或者可以在每个单独字段上定义不同的消息。例如:
from django.core.validators import RegexValidator
class PhoneField(MultiValueField):
def __init__(self, *args, **kwargs):
# Define one message for all fields.
error_messages = {
'incomplete': 'Enter a country calling code and a phone number.',
}
# Or define a different message for each field.
fields = (
CharField(error_messages={'incomplete': 'Enter a country calling code.'},
validators=[RegexValidator(r'^[0-9]+$', 'Enter a valid country calling code.')]),
CharField(error_messages={'incomplete': 'Enter a phone number.'},
validators=[RegexValidator(r'^[0-9]+$', 'Enter a valid phone number.')]),
CharField(validators=[RegexValidator(r'^[0-9]+$', 'Enter a valid extension.')],
required=False),
)
super(PhoneField, self).__init__(
error_messages=error_messages, fields=fields,
require_all_fields=False, *args, **kwargs)
必须是django.forms.MultiWidget的子类。默认值为TextInput,在这种情况下可能不是非常有用。
获取有效值的列表,并在单个值中返回这些值的“压缩”版本。例如,SplitDateTimeField是将时间字段和日期字段合并为datetime对象的子类。
此方法必须在子类中实现。
有两个可选参数:
用于尝试将字符串转换为有效的datetime.date对象的格式列表。
如果未提供input_date_formats参数,则会使用DateField的默认输入格式。
用于尝试将字符串转换为有效的datetime.time对象的格式列表。
如果未提供input_time_formats参数,则使用TimeField的默认输入格式。
两个字段可用于表示模型之间的关系:ModelChoiceField和ModelMultipleChoiceField。这两个字段都需要单个queryset参数,用于创建字段的选择。在表单验证时,这些字段将把一个模型对象(在ModelChoiceField的情况下)或多个模型对象(在ModelMultipleChoiceField的情况下)放置到cleaned_data表单的字典。
对于更复杂的用法,可以在声明表单字段时指定queryset=None,然后在窗体的__init__()方法中填充queryset
class FooMultipleChoiceForm(forms.Form):
foo_select = forms.ModelMultipleChoiceField(queryset=None)
def __init__(self, *args, **kwargs):
super(FooMultipleChoiceForm, self).__init__(*args, **kwargs)
self.fields['foo_select'].queryset = ...
可以选择一个单独的模型对像,适用于表示一个外键字段。 ModelChoiceField默认widet不适用选择数量很大的情况,在大于100项时应该避免使用它。
需要单个参数:
将导出字段选择的模型对象的QuerySet,将用于验证用户的选择。
ModelChoiceField也有两个可选参数:
默认情况下,ModelChoiceField使用的<select>小部件将在列表顶部有一个空选项。您可以使用empty_label属性更改此标签的文本(默认为"---------"),也可以禁用空白标签完全通过将empty_label设置为None:
# A custom empty label
field1 = forms.ModelChoiceField(queryset=..., empty_label="(Nothing)")
# No empty label
field2 = forms.ModelChoiceField(queryset=..., empty_label=None)
请注意,如果需要ModelChoiceField并且具有默认初始值,则不会创建空选项(不管empty_label的值)。
此可选参数用于指定要用作字段窗口小部件中选项的值的字段。确保它是模型的唯一字段,否则选定的值可以匹配多个对象。默认情况下,它设置为None,在这种情况下,将使用每个对象的主键。例如:
# No custom to_field_name
field1 = forms.ModelChoiceField(queryset=...)
将产生:
<select id="id_field1" name="field1">
<option value="obj1.pk">Object1</option>
<option value="obj2.pk">Object2</option>
...
</select>
和:
# to_field_name provided
field2 = forms.ModelChoiceField(queryset=..., to_field_name="name")
将产生:
<select id="id_field2" name="field2">
<option value="obj1.name">Object1</option>
<option value="obj2.name">Object2</option>
...
</select>
The __str__ (__unicode__ on Python 2) method of the model will be called to generate string representations of the objects for use in the field’s choices; 提供自定义表示,子类ModelChoiceField并覆盖label_from_instance。此方法将接收一个模型对象,并应返回一个适合表示它的字符串。例如:
from django.forms import ModelChoiceField
class MyModelChoiceField(ModelChoiceField):
def label_from_instance(self, obj):
return "My Object #%i" % obj.id
invalid_choice消息可以包含%(value)s并且invalid_pk_value消息可以包含%(pk)s其将被适当的值代替。
允许选择适合于表示多对多关系的一个或多个模型对象。与ModelChoiceField一样,您可以使用label_from_instance自定义对象表示,queryset是必需的参数:
将导出字段选择的模型对象的QuerySet,将用于验证用户的选择。
如果内建的字段不能满足你的需求,你可以很容易地创建自定义的字段。你需要创建django.forms.Field 的一个子类。它只要求实现一个clean() 方法和接收上面核心参数的__init__() 方法(required, label, initial, widget, help_text)。
2015年5月13日