创建一个 Form
类时,最重要的部分是定义表单的字段。每个字段都有自定义的验证逻辑,以及其他一些钩子。
注意:这里说的是字段Field级别的clean方法,不是整个表单级别的clean方法。
虽然表单字段的Field类主要使用在Form类中,但也可以直接实例化它们来使用,以便更好地了解它们是如何工作的。
每个Field的实例都有一个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.']
这个clean方法经常被我们用来在开发或测试过程中对某个字段的数据进行验证和测试。
和Form类似,每个Field也有一个has_changed()
方法(注意这不是字段的参数,而是字段的一个方法),用于判断字段的值是否发生了改变。
以下的参数是每个Field类都可以使用的。
Django的表单默认规则是每个字段都必须填写。如果提供的字段值是None或者空字符串""
,则会弹出异常。
>>> 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'
label参数用于指定自动生成的label标签的文本,来给字段添加人类友好的提示信息。如果没有设置这个参数,那么就用字段的首字母大写名字。比如下面的例子,前两个字段有,最后的comment没有label参数:
>>> from django import forms >>> class CommentForm(forms.Form): ... name = forms.CharField(label='Your name') ... url = forms.URLField(label='Your website', required=False) ... comment = forms.CharField() >>> f = CommentForm(auto_id=False) >>> print(f) <tr><th>Your name:</th><td><input type="text" name="name" required /></td></tr> <tr><th>Your website:</th><td><input type="url" name="url" /></td></tr> <tr><th>Comment:</th><td><input type="text" name="comment" required /></td></tr>
Django默认为上面的label参数后面加个冒号后缀,如果想自定义,可以使用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" required /></p> <p><label for="id_nationality">Nationality?</label> <input id="id_nationality" name="nationality" type="text" required /></p> <p><label for="id_captcha_answer">2 + 2 =</label> <input id="id_captcha_answer" name="captcha_answer" type="number" required /></p>
注意最后的captcha_answer
字段,它的label_suffix
参数和表单初始化的label_suffix
参数发生了冲突,显然前者具有更高的优先度。
为HTML页面中表单元素提供初始值。也就是input元素的value参数的值,如下所示:
>>> 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" required /></td></tr> <tr><th>Url:</th><td><input type="url" name="url" value="http://" required /></td></tr> <tr><th>Comment:</th><td><input type="text" name="comment" required /></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" required /></td></tr> <tr><th>Url:</th><td><ul class="errorlist"><li>Enter a valid URL.</li></ul><input type="url" name="url" value="http://" required /></td></tr> <tr><th>Comment:</th><td><ul class="errorlist"><li>This field is required.</li></ul><input type="text" name="comment" required /></td></tr>
上面是错误操作,因为它是在绑定一个表单,而不是初始化一个表单。要初始化一个表单,需要使用我们前面说过的表单initial参数,也就是f = CommentForm(initial=default_data, auto_id=False)
还要注意,如果提交表单时某个字段的值没有填写,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" required /><td></tr>
最重要的参数之一,指定渲染Widget时使用的widget类,也就是这个form字段在HTML页面中是显示为文本输入框?密码输入框?单选按钮?多选框?还是别的....
该参数用于设置字段的辅助描述文本。
>>> 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_p()) <p>Subject: <input type="text" name="subject" maxlength="100" required /> <span class="helptext">100 characters max.</span></p> <p>Message: <input type="text" name="message" required /></p> <p>Sender: <input type="email" name="sender" required /> A valid email address, please.</p> <p>Cc myself: <input type="checkbox" name="cc_myself" /></p>
该参数允许你覆盖字段引发异常时的默认信息。 传递的是一个字典,其键为你想覆盖的错误信息。 例如,下面是默认的错误信息:
>>> 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': '请输入你的用户名'}) >>> name.clean('') Traceback (most recent call last): ... ValidationError: ['请输入你的用户名']
可以指定多种类型的键,不仅仅针对‘requeired’错误,参考下面的内容。
指定一个列表,其中包含了为字段进行验证的函数。
参考前面的章节,学习如何编写验证器。
localize参数帮助实现表单数据输入的本地化。
设置有该属性的字段在前端页面中将显示为不可编辑状态。
该参数接收布尔值,当设置为True时,使用HTML的disabled属性禁用表单域,以使用户无法编辑该字段。即使非法篡改了前端页面的属性,向服务器提交了该字段的值,也将依然被忽略。
Django 5.0新增。
此参数允许指定当使用as_field_group()
方法渲染字段时使用的模板。默认使用 django/forms/field.html
模板。
对于每种字段类型,都有其默认的widget类型,当输入为空时返回的值,以及采取何种验证方式,转换为Python的何种对象,可用的错误信息键,表示该字段可自定义错误信息的类型。
max_length
或min_length
,如果设置了这两个参数。 否则,所有的输入都是合法的。有四个可选参数:
参数choices:用来作为该字段选项的一个二元组组成的可迭代对象(例如,列表或元组)、字典、枚举类型、或者可调用对象。格式与用于和ORM模型字段的choices参数相同。
像ChoiceField一样,只是还有两个额外的参数:coerce和empty_value。
接收一个可选的参数:input_formats。一个格式的列表,用于转换字符串为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'
接收一个可选的参数:input_formats
如果没有提供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'
max_whole_digits
, max_digits
, max_decimal_places
,max_value
, invalid, required,min_value
接收四个可选的参数:
max_value,min_value:允许的值的范围,需要赋值decimal.Decimal对象,不能直接给个整数类型。
max_digits:值允许的最大位数(小数点之前和之后的数字总共的位数,前导的零将被删除)。
decimal_places:允许的最大小数位。
三个可选的参数用于验证,max_length 、min_length和empty_value 。其中最大长度默认值320。
具有两个可选的参数用于验证:max_length和 allow_empty_file。
这个字段允许从一个特定的目录选择文件。 它有五个额外的参数,其中的path是必须的:
path:要列出的目录的绝对路径。 这个目录必须存在。
recursive:如果为False(默认值),只用直接位于path下的文件或目录作为选项。如果为True,将递归访问这个目录,其内所有的子目录和文件都将作为选项。
match:正则表达模式;只有具有与此表达式匹配的文件名称才被允许作为选项。
allow_files
:可选。默认为True。表示是否应该包含指定位置的文件。它和allow_folders
必须有一个为True。
allow_folders
可选。默认为False。表示是否应该包含指定位置的目录。
接收两个可选的参数用于验证,max_value和min_value,控制允许的值的范围。
使用ImageField需要安装Pillow(pip install pillow)。如果在上传图片时遇到图像损坏错误,通常意味着使用了Pillow不支持的格式。
>>> from PIL import Image >>> from django import forms >>> from django.core.files.uploadedfile import SimpleUploadedFile >>> class ImageForm(forms.Form): ... img = forms.ImageField() >>> file_data = {'img': SimpleUploadedFile('test.png', <file data>)} >>> form = ImageForm({}, file_data) # Pillow closes the underlying file descriptor. >>> form.is_valid() True >>> image_field = form.cleaned_data['img'] >>> image_field.image <PIL.PngImagePlugin.PngImageFile image mode=RGBA size=191x287 at 0x7F5985045C18> >>> image_field.image.width 191 >>> image_field.image.height 287 >>> image_field.image.format 'PNG' >>> image_field.image.getdata() # Raises AttributeError: 'NoneType' object has no attribute 'seek'. >>> image = Image.open(image_field) >>> image.getdata() <ImagingCore object at 0x7f5984f874b0>
两个可选参数:max_value和min_value,控制允许的值的范围。
Django3.1新增。
接收JSON编码的字段。
包含IPv4或IPv6地址的字段。
有两个可选参数:protocol和unpack_ipv4
类似MultipleChoiceField,除了需要两个额外的参数,coerce和empty_value。
需要一个必需的参数:regex,需要匹配的正则表达式。
还可以接收max_length,min_length和strip参数,类似CharField。
此字段用于在表单中表示模型的SlugField。
接收一个可选的参数:input_formats,用于尝试将字符串转换为有效的datetime.time对象的格式列表。
如果没有提供input_formats,默认的输入格式为:
'%H:%M:%S', # '14:30:59' '%H:%M', # '14:30'
可选参数:max_length、min_length、empty_value
接收一个额外的必选参数:fields,用于验证字段值的字段列表(按提供它们的顺序)。
>>> 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).']
如果内置的Field真的不能满足你的需求,还可以自定义Field。
只需要创建一个django.forms.Field
的子类,并实现clean()和__init__()
构造方法。__init__()
构造方法需要接收前面提过的那些核心参数,比如widget、required,、label、help_text、initial。
还可以通过覆盖get_bound_field()
方法来自定义访问字段的方式。
Django表单 字段定义
这两个参数不知道怎么用,老师能不能举个例子帮助理解下
老师,您好,html中没有生成输入框,代码如下: <form class="form-horizontal" action="." method="post"> {% csrf_token %} <!-- {{ form.as_p }} --> <div class="form-group"> <label for="{{ form.username.id_for_label }}" class="col-md-5 control-label" style="color:red"><span class="glyphicon glyphicon-user"></span>Username</label> <div class="col-md-6 text-left">{{ form.username }}</div> </div> <div class="form-group"> <label for="{{ form.password.id_for_label }}" class="col-md-5 control-label" style="color:blue"><span class="glyphicon glyphicon-floppy-open"></span>Password</label> <div class="col-md-6 text-left">{{ form.password }}</div> </div> <input type="submit" value="Login"> </form> 查看网页时,只显示了username和password的字段我中,没有显示输入框,请老师指点一二。谢谢。
搞定了,在视图中用local()方法,所以,才没有用显示
自定义的错误信息会报错呢 ValueError: dictionary update sequence element #0 has length 1; 2 is required
请问博主,经本人亲自尝试,发现自定义的error_messages错误提示信息无效!另外调用自定义的validators方法也是不起作用!为什么?怎么解决之?还请赐教。