创建一个表单类时,最重要的部分是定义表单的字段。每个字段都可以有自定义的验证逻辑,以及一些其它的钩子。
虽然字段类主要使用在表单类中,但你也可以直接实例化它们来使用,以便更好地了解它们是如何工作的。每个字段实例都有一个clean()方法, 它接受一个参数,然后返回“清洁的”数据或者抛出一个django.forms.ValidationError异常:
>>> from django import forms
>>> f = forms.EmailField()
>>> f.clean('foo@example.com')
'foo@example.com'
>>> 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'
另见本地化格式。
Deprecated since version 1.7: DateTimeField 与SplitDateTimeWidget 一起使用的功能被废弃并将在Django 1.9 中删除。Use SplitDateTimeField instead.
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。它们控制字段中允许的值的范围。
Using an ImageField requires that Pillow is installed with support for the image formats you use. If you encounter a corrupt image error when you upload an image, it usually means that Pillow doesn’t understand its format. To fix this, install the appropriate library and reinstall Pillow.
When you use an ImageField on a form, you must also remember to bind the file data to the form.
After the field has been cleaned and validated, the UploadedFile object will have an additional image attribute containing the Pillow Image instance used to check if the file was a valid image. UploadedFile.content_type is also updated with the image’s content type as determined by Pillow.
The max_value and min_value error messages may contain %(limit_value)s, which will be substituted by the appropriate limit.
Takes two optional arguments for validation:
These control the range of values permitted in the field.
Deprecated since version 1.7: This field has been deprecated in favor of GenericIPAddressField.
A field containing either an IPv4 or an IPv6 address.
The IPv6 address normalization follows RFC 4291 section 2.2, including using the IPv4 format suggested in paragraph 3 of that section, like ::ffff:192.0.2.0. For example, 2001:0::0:01 would be normalized to 2001::1, and ::ffff:0a0a:0a0a to ::ffff:10.10.10.10. All characters are converted to lowercase.
Takes two optional arguments:
Limits valid inputs to the specified protocol. Accepted values are both (default), IPv4 or IPv6. Matching is case insensitive.
Unpacks IPv4 mapped addresses like ::ffff:192.0.2.1. If this option is enabled that address would be unpacked to 192.0.2.1. Default is disabled. Can only be used when protocol is set to 'both'.
The invalid_choice error message may contain %(value)s, which will be replaced with the selected choice.
Takes one extra required argument, choices, as for ChoiceField.
Just like a MultipleChoiceField, except TypedMultipleChoiceField takes two extra arguments, coerce and empty_value.
The invalid_choice error message may contain %(value)s, which will be replaced with the selected choice.
Takes two extra arguments, coerce and empty_value, as for TypedChoiceField.
Takes one required argument:
A regular expression specified either as a string or a compiled regular expression object.
Also takes max_length and min_length, which work just as they do for CharField.
Deprecated since version 1.8: The optional argument error_message is also accepted for backwards compatibility but will be removed in Django 2.0. The preferred way to provide an error message is to use the error_messages argument, passing a dictionary with 'invalid' as a key and the error message as the value.
Takes one optional argument:
A list of formats used to attempt to convert a string to a valid datetime.time object.
If no input_formats argument is provided, the default input formats are:
'%H:%M:%S', # '14:30:59'
'%H:%M', # '14:30'
Takes one extra required argument:
The list of fields that should be used to validate the field’s value (in the order in which they are provided).
>>> from django.forms import ComboField
>>> f = ComboField(fields=[CharField(max_length=20), EmailField()])
>>> f.clean('test@example.com')
'test@example.com'
>>> f.clean('longemailaddress@example.com')
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,在这种情况下可能不是非常有用。
Takes a list of valid values and returns a “compressed” version of those values – in a single value. For example, SplitDateTimeField is a subclass which combines a time field and a date field into a datetime object.
This method must be implemented in the subclasses.
Takes two optional arguments:
A list of formats used to attempt to convert a string to a valid datetime.date object.
If no input_date_formats argument is provided, the default input formats for DateField are used.
A list of formats used to attempt to convert a string to a valid datetime.time object.
If no input_time_formats argument is provided, the default input formats for TimeField are used.
Two fields are available for representing relationships between models: ModelChoiceField and ModelMultipleChoiceField. Both of these fields require a single queryset parameter that is used to create the choices for the field. Upon form validation, these fields will place either one model object (in the case of ModelChoiceField) or multiple model objects (in the case of ModelMultipleChoiceField) into the cleaned_data dictionary of the form.
For more complex uses, you can specify queryset=None when declaring the form field and then populate the queryset in the form’s __init__() method:
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项时应该避免使用它。
A single argument is required:
A QuerySet of model objects from which the choices for the field will be derived, and which will be used to validate the user’s selection.
ModelChoiceField also takes two optional arguments:
By default the <select> widget used by ModelChoiceField will have an empty choice at the top of the list. You can change the text of this label (which is "---------" by default) with the empty_label attribute, or you can disable the empty label entirely by setting empty_label to None:
# A custom empty label
field1 = forms.ModelChoiceField(queryset=..., empty_label="(Nothing)")
# No empty label
field2 = forms.ModelChoiceField(queryset=..., empty_label=None)
Note that if a ModelChoiceField is required and has a default initial value, no empty choice is created (regardless of the value of empty_label).
This optional argument is used to specify the field to use as the value of the choices in the field’s widget. Be sure it’s a unique field for the model, otherwise the selected value could match more than one object. By default it is set to None, in which case the primary key of each object will be used. For example:
# No custom to_field_name
field1 = forms.ModelChoiceField(queryset=...)
would yield:
<select id="id_field1" name="field1">
<option value="obj1.pk">Object1</option>
<option value="obj2.pk">Object2</option>
...
</select>
and:
# to_field_name provided
field2 = forms.ModelChoiceField(queryset=..., to_field_name="name")
would yield:
<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; to provide customized representations, subclass ModelChoiceField and override label_from_instance. This method will receive a model object, and should return a string suitable for representing it. For example:
from django.forms import ModelChoiceField
class MyModelChoiceField(ModelChoiceField):
def label_from_instance(self, obj):
return "My Object #%i" % obj.id
The invalid_choice message may contain %(value)s and the invalid_pk_value message may contain %(pk)s, which will be substituted by the appropriate values.
Allows the selection of one or more model objects, suitable for representing a many-to-many relation. As with ModelChoiceField, you can use label_from_instance to customize the object representations, and queryset is a required parameter:
A QuerySet of model objects from which the choices for the field will be derived, and which will be used to validate the user’s selection.
如果内建的字段不能满足你的需求,你可以很容易地创建自定义的字段。你需要创建django.forms.Field 的一个子类。它只要求实现一个clean() 方法和接收上面核心参数的__init__() 方法(required, label, initial, widget, help_text)。
May 13, 2015