第九篇.form组件
我们之前在HTML页面中利用form表单向后端提交数据时,都会写一些获取用户输入的标签并且用form标签把它们包起来。与此同时我们在好多场景下都需要对用户的输入做校验,比如校验用户是否输入,输入的长度和格式等正不正确。如果用户输入的内容有错误就需要在页面上相应的位置显示对应的错误信息.。
#form组件的主要功能如下: 1.生成页面可用的HTML标签 2.对用户提交的数据进行校验 3.保留上次输入内容
1.2普通注册功能的实现
1 from django.conf.urls import url 2 from django.contrib import admin 3 from app01 import views 4 5 urlpatterns = [ 6 url(r'^admin/', admin.site.urls), 7 url(r'^reg/', views.reg), 8 ]
1 # 注册 2 def register(request): 3 error_msg = "" 4 if request.method == "POST": 5 username = request.POST.get("name") 6 pwd = request.POST.get("pwd") 7 # 对注册信息做校验 8 if len(username) < 6: 9 # 用户长度小于6位 10 error_msg = "用户名长度不能小于6位" 11 else: 12 # 将用户名和密码存到数据库 13 return HttpResponse("注册成功") 14 return render(request, "register.html", {"error_msg": error_msg})
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <title>注册页面</title> 6 </head> 7 <body> 8 <form action="/reg/" method="post"> 9 {% csrf_token %} 10 <p> 11 用户名: 12 <input type="text" name="name"> 13 </p> 14 <p> 15 密码: 16 <input type="password" name="pwd"> 17 </p> 18 <p> 19 <input type="submit" value="注册"> 20 <p style="color: red">{{ error_msg }}</p> 21 </p> 22 </form> 23 </body> 24 </html>
1.3使用form组件实现注册功能
1 from django.conf.urls import url 2 from django.contrib import admin 3 from app01 import views 4 5 urlpatterns = [ 6 url(r'^admin/', admin.site.urls), 7 url(r'^reg2/', views.reg), 8 ]
1 from django import forms 2 3 # 1.先定义好一个form组件: 4 class RegForm(forms.Form): 5 username = forms.CharField(label='用户名',min_length=6) #min_length 用于前端校验 6 pwd = forms.CharField(label="密码",widget=forms.PasswordInput) #widget用于密文 7 gender = forms.ChoiceField(choices=((1,'男'),('2','女'))) 8 9 #2.使用form组件实现注册方式 10 def register2(request): 11 form_obj = RegForm() 12 if request.method == "POST": 13 # 实例化form对象的时候,把post提交过来的数据直接传进去 14 form_obj = RegForm(data=request.POST) 15 # 调用form_obj校验数据的方法 16 if form_obj.is_valid(): #对数据进行校验 17 return HttpResponse("注册成功") 18 return render(request, "register2.html", {"form_obj": form_obj})
1 <!-- novalidate 前端不需校验--> 2 3 <!DOCTYPE html> 4 <html lang="en"> 5 <head> 6 <meta charset="UTF-8"> 7 <title>注册2</title> 8 </head> 9 <body> 10 <form action="/reg2/" method="post" novalidate autocomplete="off"> 11 {% csrf_token %} 12 <div> 13 14 <!-- 15 {{ form_obj.as_p }} 生成一个个p标签 16 {{ form_obj.errors }} form表单中所有错误 17 {{ form_obj.username }} 一个字段对应的input框 18 {{ form_obj.username.label }} 该字段的中文提示 19 {{ form_obj.username.id_for_label }} 该字段input框对应的id 20 {{ form_obj.username.errors }} 该字段所有错误 21 {{ form_obj.username.errors.0 }} 该字段的第一个错误 22 --> 23 24 25 26 <label for="{{ form_obj.name.id_for_label }}">{{ form_obj.name.label }}</label> 27 {{ form_obj.name }} {{ form_obj.name.errors.0 }} 28 </div> 29 <div> 30 <label for="{{ form_obj.pwd.id_for_label }}">{{ form_obj.pwd.label }}</label> 31 {{ form_obj.pwd }} {{ form_obj.pwd.errors.0 }} 32 </div> 33 <div> 34 <input type="submit" class="btn btn-success" value="注册"> 35 </div> 36 </form> 37 </body> 38 </html>
1.4常用字段与插件
创建Form类时,主要涉及到 【字段】 和 【插件】,
-
字段用于对用户请求数据的验证
-
插件用于自动生成HTML
1.4.1 initial
初始值,input框里面的初始值。
from django import forms
class LoginForm(forms.Form):
username = forms.CharField(
min_length=8,
label="用户名",
initial="张三" # 设置默认值
)
1.4.2 error_messages
重写错误信息。
from django import forms
class RegForm(forms.Form):
username = forms.CharField(
label='用户名',
min_length=6,
initial='张三',
error_messages={
"required": "不能为空",
"invalid": "格式错误",
"min_length": "用户名最短8位"
}
)
1.4.3 password
class LoginForm(forms.Form): ... pwd = forms.CharField( min_length=6, label="密码", widget=forms.widgets.PasswordInput(attrs={'class': 'c1'}, render_value=True) )
1.4.4 radioSelect
单radio值为字符串
class LoginForm(forms.Form): username = forms.CharField( min_length=8, label="用户名", initial="张三", error_messages={ "required": "不能为空", "invalid": "格式错误", "min_length": "用户名最短8位" } ) pwd = forms.CharField(min_length=6, label="密码") gender = forms.fields.ChoiceField( choices=((1, "男"), (2, "女"), (3, "保密")), label="性别", initial=3, widget=forms.widgets.RadioSelect() )
1.4.5 单选Select
class LoginForm(forms.Form): ... hobby = forms.ChoiceField( choices=((1, "篮球"), (2, "足球"), (3, "双色球"), ), label="爱好", initial=3, widget=forms.widgets.Select() )
1.4.6 多选Select
class LoginForm(forms.Form): ... hobby = forms.MultipleChoiceField( choices=((1, "篮球"), (2, "足球"), (3, "双色球"), ), label="爱好", initial=[1, 3], widget=forms.widgets.SelectMultiple() )
1.4.7 单选checkbox
class LoginForm(forms.Form): ... keep = forms.fields.ChoiceField( label="是否记住密码", initial="checked", widget=forms.widgets.CheckboxInput() )
1.4.8 多选checkbox
class LoginForm(forms.Form): ... hobby = forms.fields.MultipleChoiceField( choices=((1, "篮球"), (2, "足球"), (3, "双色球"),), label="爱好", initial=[1, 3], widget=forms.widgets.CheckboxSelectMultiple() )
关于choice的注意事项:
在使用选择标签时,需要注意choices的选项可以从数据库中获取,但是由于是静态字段 获取的值无法实时更新,那么需要自定义构造方法从而达到此目的。
-
方式一:
View Code1 from django.forms import Form 2 from django.forms import widgets 3 from django.forms import fields 4 from app01 import models 5 6 class RegForm(forms.Form): 7 ... 8 hobby = forms.ChoiceField( 9 choices=((1, "篮球"), (2, "足球"), (3, "双色球"), ), 10 label="爱好", 11 initial=3, 12 widget=forms.widgets.Select() 13 ) 14 15 def __init__(self, *args, **kwargs): 16 super(RegForm,self).__init__(*args, **kwargs) 17 self.fields['hobby'].choices = models.Hobby.objects.values_list('id','name')
-
方式二:ModelMultipleChoiceField
View Code1 from django import forms 2 from django.forms import fields 3 from django.forms import models as form_model 4 5 class RegForm(forms.Form): 6 ... 7 hobby = forms.ModelMultipleChoiceField( 8 query_set = models.Hobby.objects.all() 9 )
1.4.9Django Form所有内置字段
1 Field 2 required=True, 是否允许为空 3 widget=None, HTML插件 4 label=None, 用于生成Label标签或显示内容 5 initial=None, 初始值 6 help_text='', 帮助信息(在标签旁边显示) 7 error_messages=None, 错误信息 {'required': '不能为空', 'invalid': '格式错误'} 8 validators=[], 自定义验证规则 9 localize=False, 是否支持本地化 10 disabled=False, 是否可以编辑 11 label_suffix=None Label内容后缀 12 13 14 CharField(Field) 15 max_length=None, 最大长度 16 min_length=None, 最小长度 17 strip=True 是否移除用户输入空白 18 19 IntegerField(Field) 20 max_value=None, 最大值 21 min_value=None, 最小值 22 23 FloatField(IntegerField) 24 ... 25 26 DecimalField(IntegerField) 27 max_value=None, 最大值 28 min_value=None, 最小值 29 max_digits=None, 总长度 30 decimal_places=None, 小数位长度 31 32 BaseTemporalField(Field) 33 input_formats=None 时间格式化 34 35 DateField(BaseTemporalField) 格式:2015-09-01 36 TimeField(BaseTemporalField) 格式:11:12 37 DateTimeField(BaseTemporalField)格式:2015-09-01 11:12 38 39 DurationField(Field) 时间间隔:%d %H:%M:%S.%f 40 ... 41 42 RegexField(CharField) 43 regex, 自定制正则表达式 44 max_length=None, 最大长度 45 min_length=None, 最小长度 46 error_message=None, 忽略,错误信息使用 error_messages={'invalid': '...'} 47 48 EmailField(CharField) 49 ... 50 51 FileField(Field) 52 allow_empty_file=False 是否允许空文件 53 54 ImageField(FileField) 55 ... 56 注:需要PIL模块,pip3 install Pillow 57 以上两个字典使用时,需要注意两点: 58 - form表单中 enctype="multipart/form-data" 59 - view函数中 obj = MyForm(request.POST, request.FILES) 60 61 URLField(Field) 62 ... 63 64 65 BooleanField(Field) 66 ... 67 68 NullBooleanField(BooleanField) 69 ... 70 71 ChoiceField(Field) 72 ... 73 choices=(), 选项,如:choices = ((0,'上海'),(1,'北京'),) 74 required=True, 是否必填 75 widget=None, 插件,默认select插件 76 label=None, Label内容 77 initial=None, 初始值 78 help_text='', 帮助提示 79 80 81 ModelChoiceField(ChoiceField) 82 ... django.forms.models.ModelChoiceField 83 queryset, # 查询数据库中的数据 84 empty_label="---------", # 默认空显示内容 85 to_field_name=None, # HTML中value的值对应的字段 86 limit_choices_to=None # ModelForm中对queryset二次筛选 87 88 ModelMultipleChoiceField(ModelChoiceField) 89 ... django.forms.models.ModelMultipleChoiceField 90 91 92 93 TypedChoiceField(ChoiceField) 94 coerce = lambda val: val 对选中的值进行一次转换 95 empty_value= '' 空值的默认值 96 97 MultipleChoiceField(ChoiceField) 98 ... 99 100 TypedMultipleChoiceField(MultipleChoiceField) 101 coerce = lambda val: val 对选中的每一个值进行一次转换 102 empty_value= '' 空值的默认值 103 104 ComboField(Field) 105 fields=() 使用多个验证,如下:即验证最大长度20,又验证邮箱格式 106 fields.ComboField(fields=[fields.CharField(max_length=20), fields.EmailField(),]) 107 108 MultiValueField(Field) 109 PS: 抽象类,子类中可以实现聚合多个字典去匹配一个值,要配合MultiWidget使用 110 111 SplitDateTimeField(MultiValueField) 112 input_date_formats=None, 格式列表:['%Y--%m--%d', '%m%d/%Y', '%m/%d/%y'] 113 input_time_formats=None 格式列表:['%H:%M:%S', '%H:%M:%S.%f', '%H:%M'] 114 115 FilePathField(ChoiceField) 文件选项,目录下文件显示在页面中 116 path, 文件夹路径 117 match=None, 正则匹配 118 recursive=False, 递归下面的文件夹 119 allow_files=True, 允许文件 120 allow_folders=False, 允许文件夹 121 required=True, 122 widget=None, 123 label=None, 124 initial=None, 125 help_text='' 126 127 GenericIPAddressField 128 protocol='both', both,ipv4,ipv6支持的IP格式 129 unpack_ipv4=False 解析ipv4地址,如果是::ffff:192.0.2.1时候,可解析为192.0.2.1, PS:protocol必须为both才能启用 130 131 SlugField(CharField) 数字,字母,下划线,减号(连字符) 132 ... 133 134 UUIDField(CharField) uuid类型
1.5校验
1.5.1内置校验
required = True
min_length
max_length
1.5.2自定义校验
-
方式一: 写函数
View Code1 from django.shortcuts import render,HttpResponse 2 from django import forms 3 from django.core.exceptions import ValidationError 4 5 #自定义校验器 6 def checkname(values): 7 #通过校验规则,什么都不用干 8 #未通过校验规则, 9 if 'alex' in values: 10 raise ValidationError('不允许使用') 11 12 13 class RegForm(forms.Form): 14 username = forms.CharField( 15 label='用户名', 16 validators= [checkname], 17 )
-
方式二:内置校验器
View Code1 from django.shortcuts import render,HttpResponse 2 from django import forms 3 from django.core.validators import RegexValidator 4 5 class RegForm(forms.Form): 6 phone = forms.CharField( 7 validators=[RegexValidator(r'^1[3-9]\d{9}$','手机号格式不正确')], 8 ) 9 10 def reg2(request): 11 form_obj = RegForm() 12 if request.method == 'POST': 13 form_obj = RegForm(request.POST) 14 if form_obj.is_valid(): 15 return HttpResponse("注册成功") 16 return render(request, "reg2.html", {"form_obj": form_obj})
-
方式三:Hook方法
如下
1.5.3钩子
除了上面两种方式,我们还可以在Form类中定义钩子函数,来实现自定义的验证功能。
-
is_valid() 流程
View Code1 1. 执行 full_clean() 方法 2 定义错误字典 3 定义存放清洗数据的字典 4 2. 执行 _clean_fields()方法 5 循环所有字段,获取当前字段的值,并进行校验(内置校验规则,自定义校验规则) 6 1> 通过校验 7 self.clean_data[name] = value 8 如果有局部钩子,执行校验 9 通过校验 self.clean_data[name] = value 10 未通过校验 self._errors中添加当前字段错误,并将self.clean_data中当前字段的值删除掉 11 2> 未通过校验 12 self._errors 中添加当前字段错误 13 3.执行全局钩子 clean() 方法 14 1> 局部钩子 15 def clean_username(self): 16 # 通过校验规则,必须返回当前字段值 17 # 未通过校验规则,抛出异常 18 raise ValidationError('不允许使用') 19 2> 全局钩子 20 def clean(self): 21 # 通过校验规则,必须返回当前字段值 22 # 未通过校验规则,抛出异常 '__all__' 23 pass
局部钩子
from django.shortcuts import render,HttpResponse from django import forms from django.core.exceptions import ValidationError from django.core.validators import RegexValidator class RegForm(forms.Form): username = forms.CharField( label='用户名', min_length=6, initial='张三', ) # 局部钩子 def clean_username(self): # 通过校验规则,必须返回当前字段值 # 未通过校验规则, v = self.cleaned_data.get('username') if 'alex1111' in v: raise ValidationError('不允许使用233') else: return v
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <title>Title</title> 6 </head> 7 <body> 8 9 <form action="" method="post" novalidate> 10 {% csrf_token %} 11 12 <p> 13 <laber for="{{ form_obj.username.id_for_label }}">{{ form_obj.username.label }}</laber> 14 {{ form_obj.username }} 15 {{ form_obj.username.errors.0 }} 16 </p> 17 18 </body> 19 </html>
全局钩子
1 from django.shortcuts import render,HttpResponse 2 from django import forms 3 from django.core.exceptions import ValidationError 4 5 class RegForm(forms.Form): 6 pwd = forms.CharField(label='密码',widget=forms.PasswordInput) 7 re_pwd = forms.CharField(label='确认密码',widget=forms.PasswordInput) 8 9 def clean(self): 10 pwd = self.cleaned_data.get('pwd') 11 re_pwd = self.cleaned_data.get('re_pwd') 12 if pwd == re_pwd: 13 return self.cleaned_data 14 else: 15 self.add_error('re_pwd','两次密码不一致') 16 raise ValidationError('两次密码不一致')
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <title>Title</title> 6 </head> 7 <body> 8 9 <form action="" method="post" novalidate> 10 {% csrf_token %} 11 12 <p> 13 <laber for="{{ form_obj.pwd.id_for_label }}">{{ form_obj.pwd.label }}</laber> 14 {{ form_obj.pwd }} 15 {{ form_obj.pwd.errors }} 16 </p> 17 <p> 18 <laber for="{{ form_obj.re_pwd.id_for_label }}">{{ form_obj.re_pwd.label }}</laber> 19 {{ form_obj.re_pwd }} 20 {{ form_obj.re_pwd.errors }} 21 </p> 22 23 24 <button>注册</button> 25 </form> 26 27 28 </body> 29 </html>
参考博文 https://www.cnblogs.com/maple-shaw/artcles/9537309.html

浙公网安备 33010602011771号