04: Form 验证用户数据 & 生成html
目录:Django其他篇
05:ModelForm 数据验证 & 生成html & 数据库操作
目录:
- 1.1 Form作用 与 基本使用
- 1.2 from内置字段fields(数据验证)、内置插件widgets(生成html)
- 1.3 Form 验证用户数据 & 生成html 使用演示
- 1.4 使用choice字段实现radio,select,checkbox功能
- 1.5 form动态从数据库获取数据添加到select下拉菜单中
- 1.6 form验证规则中的内置钩子
- 1.7 form中自定义验证规则两种方法
1.1 Form作用 与 基本使用 返回顶部
1、form 作用
1、功能1: 验证
2、功能2: 生成html标签
3、功能3: HTML Form提交保留上次提交数据
4、功能4: 初始化页面显示内容
2、form使用原则
1、 新url方式操作(一定要用form方式生成html,避免提交刷新页面,丢失当前页面中填的值)
2、 发Ajax请求时可以不用form生成html标签,仅用form做验证,因为ajax请求本身不刷新页面,不必担心填
的值会丢失,当然使用form生成html也是可以的
3、form基本使用:对 login.html提交密码做简单长度验证
from django.shortcuts import render,HttpResponse,redirect from app01.forms import UserForm def login(request): if request.method == 'GET': obj = UserForm() return render(request,'login.html',{'obj':obj}) elif request.method == 'POST': obj = UserForm(request.POST) r1 = obj.is_valid() if r1: print(obj.cleaned_data) else: print(obj.errors) return render(request,'login.html',{'obj':obj})
from django import forms from django.forms import fields class UserForm(forms.Form): #1: 这里的name必须要和input框中name的值 name = fields.CharField( error_messages={'required':'用户名不能为空'}, ) #2: 这里的password必须是input框中name的值 password = fields.CharField( min_length=6, max_length=10, error_messages={'required':'密码不能为空', 'min_length':'密码长度不能小于6', 'max_length':'密码长度不能大于12', } )
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> </head> <body> <form method="POST" action="/login/"> <p>用户名:<input name="name" type="text">{{ obj.errors.name.0 }}</p> <p>密 码:<input name="password" type="text">{{ obj.errors.password.0 }}</p> <p><input type="submit" value="提交"></p> </form> </body> </html>
4、生成HTML更简单的三种方法,但是耦合性太强,不好定制(不建议使用)
1. { obj.as_p }
2. { obj.as_ul }
3. { obj.as_table }
1.2 from内置字段fields(数据验证)、内置插件widgets(生成html) 返回顶部
######################## 1、常用的form内置字段 ######################### #1. Field required=True, # 是否允许为空 widget=None, # HTML插件 label=None, # 用于生成Label标签或显示内容 initial=None, # 初始值 help_text='', # 帮助信息(在标签旁边显示) error_messages=None, # 错误信息 {'required': '不能为空', 'invalid': '格式错误'} show_hidden_initial=False, # 是否在当前插件后面再加一个隐藏的且具有默认值的插件(可用于检验两次输入是否一致) validators=[], # 自定义验证规则 localize=False, # 是否支持本地化(比如需要本地时间而不是utc时间) disabled=False, # 是否可以编辑 label_suffix=None # Label内容后缀 #2. CharField(Field) max_length=None, # 最大长度 min_length=None, # 最小长度 strip=True # 是否移除用户输入空白 #3. EmailField(CharField) # 必须为邮件格式 #4. ChoiceField(Field) choices=(), # 选项,如:choices = ((0,'上海'),(1,'北京'),) required=True, # 是否必填 widget=None, # 插件,默认select插件 label=None, # Label内容 initial=None, # 初始值 help_text='', # 帮助提示 #5. FileField(Field) # 上传文件 allow_empty_file=False # 是否允许空文件 #6. 时间格式化(必须输入下面要求的格式) DateField(BaseTemporalField) # 格式:2015-09-01 TimeField(BaseTemporalField) # 格式:11:12 DateTimeField(BaseTemporalField) # 格式:2015-09-01 11:12 ######################## 2、不常用的form内置字段 ######################### #7. IntegerField(Field) max_value=None, # 最大值 min_value=None, # 最小值 #8. RegexField(CharField) # 自定义正则表达式 regex, # 自定制正则表达式 max_length=None, # 最大长度 min_length=None, # 最小长度 error_message=None, # 忽略,错误信息使用 error_messages={'invalid': '...'} #9. max_value=None, # 最大值 min_value=None, # 最小值 max_digits=None, # 总长度 decimal_places=None, # 小数位长度 #10. ImageField(FileField)上传图片 注:需要PIL模块,pip3 install Pillow 以上两个字典使用时,需要注意两点: - form表单中 enctype="multipart/form-data" - view函数中 obj = MyForm(request.POST, request.FILES) #11. BooleanField(Field) # 必须是布尔值 #12. ComboField(Field) # 使用多个验证(比如:即验证最大长度20,又验证邮箱格式) fields.ComboField(fields=[fields.CharField(max_length=20), fields.EmailField(),]) #13. FilePathField(ChoiceField) # 文件选项,目录下文件显示在页面中 path, # 文件夹路径 #14. GenericIPAddressField protocol='both', # both,ipv4,ipv6支持的IP格式 unpack_ipv4=False # 解析ipv4地址,如果是::ffff:192.0.2.1时候,可解析为192.0.2.1, PS:protocol必须为both才能启用 #15. URLField(Field) # 必须是url格式 #16. ModelMultipleChoiceField(ModelChoiceField)
######################### 1、常用的widgets内置插件 ######################### # TextInput(Input) # PasswordInput(TextInput) # EmailInput(TextInput) # Textarea(Widget) # FileInput # Select # SelectMultiple # RadioSelect # CheckboxInput # CheckboxSelectMultiple ######################## 2、不常用的widgets内置插件 ######################### # DateInput(DateTimeBaseInput) # DateTimeInput(DateTimeBaseInput) # TimeInput(DateTimeBaseInput) # NumberInput(TextInput) # URLInput(TextInput) # ClearableFileInput # MultipleHiddenInput # SplitDateTimeWidget # SplitHiddenDateTimeWidget # SelectDateWidget # HiddenInput(TextInput) # NullBooleanSelect
1.3 Form 验证用户数据 & 生成html 使用演示 返回顶部
1、Form验证数据、生成html
from django.shortcuts import HttpResponse,render from app01 import models from app01.forms import FM def login(request): if request.method == 'GET': obj = FM() # 初始化操作,将字典中的值显示到页面,作为初始化值 return render(request,'login.html',{'obj':obj}) elif request.method == 'POST': # 获取用户所有数据 # 每条请求数据的验证 # 成功:获取所有正确信息 # 失败:显示错误信息 obj = FM(request.POST,request.FILES) #将POST中提交的所有数据传给处理类(类中做校验) data = obj.is_valid() #类中对输入信息校验结果,符合返回True,否则返回False if data: # obj.cleaned_data 中获取了用户POST中所有正确信息,格式是字典 print(obj.cleaned_data) # 将获取的正确信息字典传入进去就可以直接创建到数据库中 # models.UserInfo.objects.create(**obj.cleaned_data) else: print(obj.errors) return render(request,'login.html',{'obj':obj}) # 法get请求时给页面初始化值 ''' # 从数据库获取数据,传入给initial的值必须是一个字典,且key必须是页面中的字段 dic= { 'user':'tom', 'pwd':'123', 'email':'tom@qq.com', 'city':2, 'mcity':[1,2] } # obj = FM(initial=dic) # 初始化操作,将字典中的值显示到页面,作为初始化值 # 为了使用户以get请求也能看到页面内容,在这里也要传入obj '''
from django import forms #我们定义的类必须继承forms.Form from django.forms import widgets #widgets是插件,可以生成input框 from django.forms import fields #字段 class FM(forms.Form): # 字段本身自己只做验证 user = fields.CharField( error_messages={'required':'用户名不能为空'}, label="用户名", #在input框前面添加一个提示信息,比如“用户名” initial='root', #在input框中可以设置一个默认值 ) pwd = fields.CharField(max_length=12, min_length=6, error_messages={'required':'密码名不能为空', 'min_length':'密码长度不能小于6', 'max_length':'密码长度不能大于12' }, widget=widgets.PasswordInput(attrs={'class':'c1'}), #变成密码input框 ) email = fields.EmailField(error_messages={'required':'邮箱不能为空','invalid':'邮箱格式错误',}, help_text='必须输入邮箱格式' ) f = fields.FileField() city = fields.ChoiceField( choices=[(0,'上海'),(1,'广州'),(2,'北京')] ) mcity = fields.MultipleChoiceField( choices=[(0,'上海'),(1,'广州'),(2,'北京')] )
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> </head> <body> <form action="/login/" method="POST"> <p>{{ obj.user.label }}: {{ obj.user }} {{ obj.errors.user.0 }}</p> <p>{{ obj.pwd.label }}{{ obj.pwd }} {{ obj.errors.pwd.0 }}</p> <p>{{ obj.email }} {{ obj.errors.email.0 }} {{ obj.email.help_text }}</p> <p>{{ obj.f }} {{ obj.errors.f.0 }}</p> <p>{{ obj.p }} {{ obj.errors.p.0 }}</p> <p>{{ obj.city }} {{ obj.errors.city.0 }}</p> <p>{{ obj.mcity }} {{ obj.errors.mcity.0 }}</p> <input type="submit" value="提交"> </form> <!-- 1、obj.errors获取到的就是这样的一端html字符串 --> <!-- 1、 obj.user.label 标签显示内容(如:用户名) obj.user.label_tag 2、 obj.user 自动生成一个input标签,这种表自动保留上一次提交的数据功能 3、 obj.errors.user.0 获取字段错误信息(提取到user字段) obj.errors 所有字段错误信息的html字符串 obj.user.errors 错误信息(返回html标签) <ul class="errorlist"><li>用户名不能为空</li></ul> 4、 obj.email.help_text 获取提示帮助信息(必须输入邮箱格式) --> <!-- 2、obj.errors获取到的就是这样的一端html字符串 --> <!-- <ul class="errorlist"> <li>user<ul class="errorlist"><li>用户名不能为空</li></ul></li> <li>pwd<ul class="errorlist"><li>密码名不能为空</li></ul></li> </ul> --> </body> </html>
2、生成HTML常用语法
1、 obj.user.label 标签显示内容(如:用户名)
obj.user.label_tag
2、 obj.user 自动生成一个input标签,这种表自动保留上一次提交的数据功能
3、 obj.errors.user.0 获取字段错误信息(提取到user字段)
obj.errors 所有字段错误信息的html字符串
obj.user.errors 错误信息(返回html标签)<ul class="errorlist"><li>用户名不能为空</li></ul>
4、 obj.email.help_text 获取提示帮助信息(必须输入邮箱格式)
3、操作form对象、数据验证
1. obj = FM(request.POST) #将POST中提交的所有数据传给处理类(类中做校验)
2. obj.is_valid() #类中对输入信息校验结果,符合返回True,否则返回False
3. obj.cleaned_data=obj.clean() #用户POST中所有正确信息,格式就是字典
#{'mcity': ['0'], 'user': 'root', 'city': '0', }
4. obj.errors # 所有错误信息的html字符串(ul li格式)
obj.errors.get('user') # user字段错误信息的html字符串(ul li格式)
obj.errors.get('user')[0] #[0]user字段错误信息的错误信息的字符串
1.4 使用choice字段实现radio,select,checkbox功能 返回顶部
# 方法1: user = fields.CharField( initial=2, widget=widgets.RadioSelect(choices=((1,'上海'),(2,'北京'),)) ) # 方法2: user = fields.ChoiceField( choices=((1, '上海'), (2, '北京'),), initial=2, widget=widgets.RadioSelect )
# 方法1: user = fields.CharField( initial=2, widget=widgets.Select(choices=((1,'上海'),(2,'北京'),)) ) # 方法2: user = fields.ChoiceField( choices=((1, '上海'), (2, '北京'),), initial=2, widget=widgets.Select )
user = fields.MultipleChoiceField( choices=((1,'上海'),(2,'北京'),), initial=[1,], widget=widgets.SelectMultiple )
user = fields.CharField( widget=widgets.CheckboxInput() )
user = fields.MultipleChoiceField( initial=[2, ], choices=((1, '上海'), (2, '北京'),), widget=widgets.CheckboxSelectMultiple )
1.5 form动态从数据库获取数据添加到select下拉菜单中 返回顶部
1、原理介绍
#1 由于user_type是类中的静态字段,程序一启动,就将值放到fields字段中了
#2 所以后面数据库修改后user_type的值还是从fields字段中获取的,必须重启程序才能更新数据到页面
#3 为了实现不必重启程序,我们必须要重写UserInfoForm类的构造方法(每次实例化类都会执行这个构造方法)
#4 每次刷新页面就会调用UserInfoForm类的构造方法,在构造方法中定义每次刷新网页时再从数据库取一次值,将值赋值给fields对应字段
2、实现动态从数据库获取数据添加到select下拉菜单中三种方法
from django.shortcuts import render from app01 import models def index(request): from app01.forms import UserInfoForm obj = UserInfoForm() # 这样就可以实现不必重启服务,数据库更新后前台刷新即可看到新数据 # obj.fields['user_type'].choices = models.UserType.objects.values_list('id','name') return render(request,'index.html',{'obj':obj})
from django.db import models from django.db import models class UserType(models.Model): name = models.CharField(max_length=32) def __str__(self): return self.name
from django import forms from django.forms import fields #fields字段专门用于验证 from django.forms import widgets #widgets专门用于生成html标签 from app01 import models class UserInfoForm(forms.Form): # 方法1 和 方法2 需要重写构造方法 user_type1 = fields.ChoiceField(choices=[],widget=widgets.Select) user_type2 = fields.CharField(widget=widgets.Select(choices=[])) def __init__(self,*args,**kwargs): super(UserInfoForm,self).__init__(*args,**kwargs) self.fields['user_type1'].choices = models.UserType.objects.values_list('id','name') self.fields['user_type2'].widget.choices= models.UserType.objects.values_list('id','name') # 方法3: from django.forms.models import ModelChoiceField, ModelMultipleChoiceField # 1 这种方法不必重写构造方法,页面数据库数据就会更新到页面 # 2 但要使用这种方法在创建表的类时必须定义 def __str__(self) user_type3 = ModelChoiceField( empty_label='请选择用户类型', #选择框中的提示信息 queryset=models.UserType.objects.all(), to_field_name='name', #指定那个字段作为value )
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <p>{{ obj.user_type1 }}</p> <p>{{ obj.user_type2 }}</p> <p>{{ obj.user_type3 }}</p> <input type="submit" value="提交"> </body> </html>
1.6 form验证规则中的内置钩子 返回顶部
1. from验证经历的顺序(搜索:Form and field validation)
1、拿到字段:用户发送一堆数据,根据form循环,拿到第一个字段
2、正则匹配:先进行fields默认正则表达式判断,然后进行自定的正则表达式判断(如果有)
3、字段钩子函数:然后执行字段的钩子函数,接着进行第二个字段,然后是第二个字段钩子函数...
4、clean钩子函数:字段钩子函数执行完了再执行clean钩子函数进行整体验证
5、_post_clean: 最后执行_post_clean钩子做其他验证
2、 form验证的错误信息存放位置
1、字段钩子错误信息放到对应的字段中 (obj.error中对应的字段字典)
2、整体错误信息会放到 {"__all__":[],}中等价于{'NON_FIELD_ERRORS':[],} (如:执行clean)
3、forms.py文件中使用这三种钩子
from django import forms from django.forms import fields #fields字段专门用于验证 from app01 import models from django.core.exceptions import ValidationError class RegisterForm(forms.Form): user = fields.CharField() email = fields.EmailField() pwd = fields.EmailField() #1 clean_字段名 是字段钩子(每个字段都有对应的这个钩子):如判断:“用户名已存在” def clean_user(self): # self.cleand_data['user']是用户提交的数据' c = models.User.objects.filter(name=self.cleand_data['user']).count() if not c: return self.cleand_data['user'] #必须要有返回值 else: raise ValidationError('用户名已存在',code='xxx') #2 clean钩子对整体验证:如判断“用户名或密码错误” def clean(self): c = models.User.objects.filter( name=self.cleand_data['user'], pwd=self.cleand_data['pwd']).count() if c: return self.cleand_data #正确的值必须return回去 else: raise ValidationError('用户名或密码错误') #3 在这里可以做 其他验证 def _post_clean(self): pass
1.7 form中自定义验证规则两种方法 返回顶部
from django.forms import Form from django.forms import widgets from django.forms import fields from django.core.validators import RegexValidator class MyForm(Form): user = fields.CharField( validators=[RegexValidator(r'^[0-9]+$', '请输入数字'), RegexValidator(r'^159[0-9]+$', '数字必须以159开头')], )
import re from django.forms import Form from django.forms import widgets from django.forms import fields from django.core.exceptions import ValidationError # 自定义验证规则 def mobile_validate(value): mobile_re = re.compile(r'^(13[0-9]|15[012356789]|17[678]|18[0-9]|14[57])[0-9]{8}$') if not mobile_re.match(value): raise ValidationError('手机号码格式错误') class PublishForm(Form): # 使用自定义验证规则 phone = fields.CharField(validators=[mobile_validate, ], error_messages={'required': '手机不能为空'}, widget=widgets.TextInput(attrs={'class': "form-control", 'placeholder': u'手机号码'}))
作者:学无止境
出处:https://www.cnblogs.com/xiaonq
生活不只是眼前的苟且,还有诗和远方。