表单系统的核心部分是Django 的Form 类;Form 类描述一个表单并决定它如何工作和展现。
就像模型类的属性映射到数据库的字段一样,表单类的字段会映射到HTML 的表单<input>元素(或其它表单元素)
构建一个简单表单的流程
1,在form.py中定义表单类
from django import forms
class NameForm(forms.Form):
your_name = forms.CharField(label='Your name', max_length=100)
2,在views.py中实例化表单与处理表单数据
from django.shortcuts import render
from django.http import HttpResponseRedirect
from .forms import NameForm
def get_name(request):
# 如果这是一个POST请求,我们就需要处理表单数据
if request.method == 'POST':
# 创建一个表单实例,并且使用请求中的数据填充表单
form = NameForm(request.POST)
# 检查数据有效性:
if form.is_valid():
# 在需要时,可以在form.cleaned_date中处理数据
# ...
# 重定向到一个新的URL:
return HttpResponseRedirect('/thanks/')
# 如果是GET或者其它请求方法,我们将创建一个空的表单。
else:
form = NameForm()
return render(request, 'name.html', {'form': form})
3,在html文件中使用表单模板
<form action="/your-name/" method="post">
{% csrf_token %}
{{ form }}
<input type="submit" value="Submit" />
</form>
注:为了上传文件,需要确保<form>元素正确定义enctype 为"multipart/form-data" :
<form enctype="multipart/form-data" method="post" action="/foo/">
</form>
实例化表单类时:
>>> f = ContactFormWithMugshot(request.POST, request.FILES)
窗口小部件(Widget)
每个表单字段都有一个对应的Widget 类,它对应一个HTML 表单部件,如<input type="text">
在大部分情况下,字段都具有一个合理的默认Widget。 例如,默认情况下,CharField 具有一个TextInput Widget,它在HTML 中生成一个<input type="text">
Widget 负责渲染HTML和提取GET/POST 字典中的数据。
注:由内置小部件生成的HTML使用HTML5语法;它使用布尔属性,如checked,而不是checked='checked'的XHTML样式
内置小部件有:
TextInput -->呈现为:<input type =“text” ...>
PasswordInput -->呈现为:<input type =“password” ...>
接收一个可选的参数:render_value; 决定在验证错误后重新显示表单时,Widget 是否填充(默认为False)
Textarea -->呈现为:<textarea>...</textarea>
DateInput/DateTimeInput /TimeInput -->呈现为:<input type =“text” ...>;接收的参数与TextInput 相同,但是带有一些可选的参数,如format
EmailInput -->呈现为:<input type =“email” ...>
URLInput -->呈现为:<input type =“url” ...>
HiddenInput -->呈现为:<input type =“hidden” ...>
Textarea -->呈现为:<textarea>...</textarea>
DateInput/DateTimeInput /TimeInput -->呈现为:<input type =“text” ...>;接收的参数与TextInput 相同,但是带有一些可选的参数,如format
CheckboxInput -->呈现为:<input type="checkbox" ...>;可选参数 check_test
Select -->呈现为: <select><option ...>...</select>;属性 choices
SelectMultiple -->允许多个选择:<select multiple="multiple">...</select>
RadioSelect -->呈现为:<ul><li><input type="radio" name="..."></li>...</ul>
FileInput -->呈现为:<input type="file" ...>
ClearableFileInput -->呈现为:<input type =“file” ...> with an additional checkbox input to clear the field’s value, if the field is not required and has initial data.
内建字段类
注:所有的Field子类都默认带有required=True
一个表单的字段本身就是类;他们管理表单数据,并在提交表单时执行验证。
1,BooleanField--> class BooleanField(**kwargs)
默认的Widget:CheckboxInput
规范化为:Python 的True 或 False。
错误信息的键:required
2,CharField -->class CharField(**kwargs)
默认的Widget:TextInput
错误信息的键:min_length, max_length, required
参数:max_length/min_length,确保字符串的最大和最小长度;strip,(默认为True)该值将被剥离前导和尾随空格。
3,ChoiceField
默认的Widget:Select
可选参数:choices,用来作为该字段选项的一个二元组组成的可迭代对象(例如,列表或元组)或者一个可调用对象
错误信息的键:required, invalid_choice
4,DateField -->class DateField(**kwargs)
默认的Widget:DateInput
规范化为:一个Python datetime.date 对象
错误信息的键:required, invalid
可选参数:input_formats,一个格式的列表,用于转换一个字符串为datetime.date 对象
#默认输入格式为:
['%Y-%m-%d', # '2006-10-25'
'%m/%d/%Y', # '10/25/2006'
'%m/%d/%y'] # '10/25/06'
5,DateTimeField
默认的Widget:DateTimeInput
规范化为:一个Python datetime.datetime 对象
错误信息的键:required, invalid
可选参数:input_formats,一个格式的列表,用于转换一个字符串为datetime.datetime 对象
#默认输入格式为:
['%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'
6,TimeField
默认的Widget:TextInput
规范化为:一个Python 的datetime.time 对象
错误信息的键:required, invalid
可选参数:input_formats,用于尝试将字符串转换为有效的datetime.time对象的格式列表。
#默认输入格式为:
'%H:%M:%S', # '14:30:59'
'%H:%M', # '14:30'
7,DecimalField
默认的Widget:当Field.localize 是False 时为NumberInput,否则为TextInput。
规范化为:一个Python decimal
错误信息的键:max_whole_digits, max_digits, max_decimal_places, max_value, invalid, required, min_value
可选参数:
max_value/min_value,控制字段中允许的值的范围,应该以decimal.Decimal 值给出;
max_digits,值允许的最大位数 ; decimal_places,允许的最大小数位
8,FloatField
默认的Widget:当Field.localize 是False 时为NumberInput,否则为TextInput
规范化为:一个Float 对象
错误信息的键:max_value, invalid, required, min_value
可选参数:max_value/min_value,控制字段中允许的值的范围
9,IntegerField
默认的Widget:当Field.localize 是False 时为NumberInput,否则为TextInput。
规范化为:一个Python 整数或长整数
错误信息的键:max_value, invalid, required, min_value
可选参数:max_value/min_value,控制字段中允许的值的范围
10,EmailField
默认的Widget:EmailInput
错误信息的键:required, invalid
验证给出的值是一个合法的邮件地址,使用一个适度复杂的正则表达式
11,MultipleChoiceField
默认的Widget:SelectMultiple
错误信息的键:invalid_list, invalid_choice, required
12,FileField
默认的Widget:ClearableFileInput
规范化为:一个UploadedFile 对象,它封装文件内容和文件名为一个单独的对象
错误信息的键:missing, invalid, required, empty, max_length
可选参数:max_length,文件名的最大长度 ;allow_empty_file,允许文件内容为空。
13,ImageField
默认的Widget:ClearableFileInput
规范化为:一个UploadedFile 对象,它封装文件内容和文件名为一个单独的对象
错误信息的键:missing, invalid, required, empty, invalid_image
验证文件数据已绑定到表单,并且该文件具有Pillow理解的图像格式;
注:使用ImageField需要安装Pillow并支持您使用的图像格式。
核心字段参数
required-->表示字段的值不能为空;默认值为required = True
label -->该参数可让你指定字段“对人类友好”的标签
label_suffix -->设置标签后缀
initial -->指定渲染未绑定的字段的初始值
注:如果某个字段的值没有给出,initial 值不会作为“后备”的数据;initial 值只用于原始表单的显示
widget --> 指定渲染Widget时使用的widget 类
error_messages -->覆盖字段引发的异常中的默认信息。 传递的是一个字典,其键为想覆盖的错误信息
validators -->可以为字段提供一个验证函数的列表
help_text -->指定Field的描述文本
localize -->可以实现表单数据输入的定位,以及渲染输出
disabled -->当设置为True时,禁用表单域,以使用户无法编辑
Forms API
Form.is_bound-->是绑定表单则返回True
不包含数据的表单称为未绑定表单,当render给用户时,它将为空或包含默认的值;
包含数据的表单称为绑定表单,因此可以用来检验数据是否合法。
注:传递一个空的字典将创建一个带有空数据的绑定的表单,如 f = ContactForm({})
Form.errors -->获得错误信息的一个字典;错误信息保存在列表中是因为字段可能有多个错误信息
Form.clean()-->当需要为相互依赖的字段添加自定义的验证时,可以重写Form的clean()方法。
Form.non_field_errors() -->返回Form.errors 中不是与特定字段相关联的错误
Form.is_valid()-->验证数据,返回一个表示数据是否合法的布尔值
Form.cleaned_data-->保存验证后(通过is_valid() 成功验证)的表单数据的一个字典;字典中只包含合法的字段,只包含Form中定义的字段
Form.has_changed() -->检查表单的数据是否从初始数据发生改变
Form.changed_data-->返回一个包含那些在表单的绑定数据中的值(通常为request.POST)与原始值发生改变的字段的名字列表
Form.fields -->访问表单中的字段
>>> for row in f.fields.values(): print(row)
>>> f.fields['name']
Form.error_css_class / Form.required_css_class
Form类具有上面这一对钩子,可以使用它们来添加class 属性给必填的行或有错误的行
Form.initial -->动态初始值
>>> f = ContactForm(initial={'subject': 'Hi there!'})
这些值只显示在没有绑定的表单中,即使没有提供特定值它们也不会作为后备的值。
Form.auto_id -->id 和label 的行为使用Form构造函数的auto_id 参数控制。 这个参数必须为True、False 或者一个字符串。
默认情况下,auto_id 设置为'id_%s';
auto_id =True :有lable和id,此时id的值为Form类中的字段名,有空格的会改为_
auto_id =False :没有lable标签和id属性
Form.label_suffix -->定义标签后缀,默认为 :(英文版)
Form.prefix -->可以将几个Django Form放在一个<form> 标签中;为了给每个Form一个自己的命名空间,可以使用prefix 关键字参数
表单模板
输出选项:必须自己提供<ul> 或<table> 元素,还有</form> 和<form> 以及<input type="submit"> 标签
{{ form.as_table }} 以表格的形式将它们渲染在<tr> 标签中
{{ form.as_p }} 将它们渲染在<p> 标签中
{{ form.as_ul }} 将它们渲染在<li> 标签中
手动渲染字段,举例:
<div class="fieldWrapper">
{{ form.message.errors }}
<label for="{{ form.message.id_for_label }}">Your message:</label>
{{ form.message }}
</div>
或
<div class="fieldWrapper">
{{ form.subject.errors }}
{{ form.subject.label_tag }}
{{ form.subject }}
</div>
{{ field }} 中的属性:
{{ field.label }} -->字段的label名
{{ field.label_tag }} -->包含在HTML <label> 标签中的字段Label
{{ field.id_for_label }} -->用于这个字段的ID
{{ field.value }} -->字段的值
{{ field.html_name }} -->输入元素的name 属性中将使用的名称
{ field.help_text }} -->与该字段关联的帮助文档。
{{ field.errors }}-->输出一个<ul class="errorlist">,包含这个字段的验证错误信息
{{ field.is_hidden }} -->如果字段是隐藏字段,则为True。
{{ field.field }} -->表单类中的Field 实例,可以使用它来访问Field属性,例如{{ char_field.field.max_length }}
表单和字段验证
表单验证发生在数据验证之后;所有以下验证方法都可以抛出ValidationError
表单验证步骤:
1,Field上的to_python()方法验证,它强制该值转为正确的数据类型,或者引发ValidationError。这个方法从Widget 接收原始的值并返回转换后的值
2,Field上的validate()方法处理不适合验证器验证的特定字段。在任何错误上会引发ValidationError;当遇到不可以或不想放在验证器中的验证逻辑时,应该覆盖它来处理验证。
3,Field上的run_validators()方法运行所有字段的验证器,并将所有错误聚合到单个ValidationError中。 不应该重写此方法。
4,Field子类上的clean()方法负责以正确的顺序运行to_python(),validate()和run_validators()并传播它们的错误。 此方法返回 clean data,然后将其插入到表单的cleaned_data字典中。
5,在Form子类上调用clean_ <fieldname>()方法 。 这个方法用于特定属性值相关的验证,这个验证与字段的类型无关。此方法的返回值将替换cleaned_data中的现有值。
6,表单子类的clean()方法可以执行需要访问多个表单字段的验证。 如“如果提供了字段A,则字段B必须包含有效的电子邮件地址”。 如果愿意,此方法可以返回完全不同的字典,该字典将作为cleaning_data。
注:Form.clean()引发的任何错误都不会与任何字段相关联。 它们位于一个特殊的“字段”(称为__all__),如果需要,可以通过non_field_errors()方法访问它。 如果要将错误附加到表单中的特定字段,则需要调用add_error()。
抛出异常规范写法:
#抛出一个异常(规范写法!)
raise ValidationError(
_('Invalid value: %(value)s'),
code='invalid',
params={'value': '42'},
)
#同时抛出多个异常
raise ValidationError([
ValidationError(_('Error 1'), code='error1'),
ValidationError(_('Error 2'), code='error2'),
])
内置验证器:
class RegexValidator(regex=None, message=None, code=None, inverse_match=None, flags=0)
参数:
regex-->进行匹配的正则表达式
message-->验证失败时ValidationError所使用的错误信息。 默认为"Enter a valid value"。
code-->验证失败时ValidationError所使用的错误代码。 默认为"invalid"。
inverse_match-->regex的匹配模式。 默认为False。为True时,则正则匹配上时抛出 ValidationError异常
flags-->编译正则表达式字符串regex时所用的标识,默认为 0
class EmailValidator(message=None, code=None, whitelist=None)
message-->验证失败时ValidationError所使用的错误信息。 默认为"Enter a valid email address"。
code-->验证失败时ValidationError所使用的错误代码。 默认为"invalid"。
whitelist-->所允许的邮件域名的白名单
自定义验证器:
#定义验证器
def validate_even(value):
if value % 2 != 0:
raise ValidationError(
_('%(value)s is not an even number'),
params={'value': value},
)
#在模型中使用
class MyModel(models.Model):
even_field = models.IntegerField(validators=[validate_even])
#在表单中使用
class MyForm(forms.Form):
even_field = forms.IntegerField(validators=[validate_even])
模型和表单
实际上,如果你的表单打算直接用来添加和编辑Django 的模型,ModelForm 可以节省你的许多时间、精力和代码,因为它将根据Model 类构建一个表单以及适当的字段和属性。
class ModelForm:
Django 提供的一个辅助类,让你可以从Django 的模型创建与该模型紧密映射的表单Form。
示例:
from django.forms import ModelForm
from myapp.models import Article
class ArticleForm(ModelForm):
class Meta:
model = Article
fields = ['pub_date', 'headline', 'content', 'reporter']
生成的Form类中将具有和指定的模型字段对应的表单字段,顺序为fields 属性中指定的顺序。
每个模型字段有一个对应的默认表单字段:模型字段 CharField --> 表单字段 CharField
ForeignKey --> ModelChoiceField
ManyToManyField --> ModelMultipleChoiceField
如果模型字段设置了blank=True,那么表单字段的required字段会设置为False值。 否则,required=True。
表单字段的label 设置为模型字段的verbose_name,并将第一个字母大写。
如果模型字段设置了choices,那么表单字段的widget将会设置为Select,选择项从模型字段的choices而来。