web前端框架之自定义form表单验证
自定义form验证初试
1 1、在后端创建一个类MainForm,并且在类中自定义host ip port phone等,然后写入方法,在post方法中创建MainForm对象,
并且把post方法中的self(这里的self指代 的前端的ip,端口等)传入到这个MainForm方法中,在check_valid方法中定义一个
参数handler代指传入的self,然后遍历MainForm对象中的属性,然后用handler.get_argument(key)的方法让前端的post
对应后端的post,前端的ip对应后端的ip。之后用re的match方法来让用户输入的内容对应正则表达式 2 2、在方法中定义一个字典,让用户输入的内容当作value传入到这个字典中,并且当作这个方法的返回值,之后由于这个方法的返
回值有两个,所以对象执行这个方法的时候去赋值,需要定义两个变量来接收 3 注意这里的两个类中的两个self是不一样的 4 1、 为每个表单写一个form 5 2、 让form的字段和HTML中的字段一致(post、ip等)
#/usr/bin/env python import tornado.ioloop import tornado.web import re class MainForm(object): def __init__(self): self.host = "(.*)" self.ip = "^(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}$" self.port = '(\d+)' self.phone = '^1[3|4|5|8][0-9]\d{8}$' def check_valid(self, handler): flag=True #创建一个字段 value_dict={} #__dict__以字典的形式显示类中的属性,key为host,ip等,value为正则表达式,input_value为用户输入的值 for key,regular in self.__dict__.items(): #这里handler指代前端的host,ip等。这里让前端的host,ip等和后端的host,ip等对应 input_value=handler.get_argument(key) #这里比对正则表达式和用户输入的值,如果对应那么就是val就是true val=re.match(regular,input_value) if not val: flag=False value_dict[key]=input_value return flag,value_dict class MainHandler(tornado.web.RequestHandler): def get(self): self.render("index.html") def post(self, *args, **kwargs): obj=MainForm() #获取用户输入的内容,和正则表达式匹配,self指代前端host,ip等,这里是把后端的host和ip传入和前端的host对应 #由于方法中有两个返回值,所以这里要定义两个 is_valid,value_dict=obj.check_valid(self) print(is_valid) #如果全部验证成功,那么将用户输入的所有内容全部放到字典中 if is_valid: print(value_dict) settings={ "template_path":"views", } application = tornado.web.Application([ (r"/index", MainHandler), ],**settings) if __name__ == "__main__": # 下面是创建了socket,循环,以及epoll io多路复用 socket运行起来 application.listen(8002) tornado.ioloop.IOLoop.instance().start()
优化
1 如果要建立多个form的时候,这个时候在后台的方法就重叠了。所以这里可以自定义一个类,让这个方法放入到这个类中,之后创建一个form就继承一次这个类。tornado里面没有这样的方式所以要自己定义,但是其他的web框架里面都是这种方式的 2 将具体的验证放到了对象中,有利于验证多个需要验证的时候分别有各自的验证规则 3 4 下面思想: 5 1、首先把相同的方法写到一个类中, 6 2、创建一个新的登录验证页面,利用模板语言把如果出错就在页面显示出来 7 3、在后台中创建四个类,一个类是方法的类,一个是正则表达式的类,一个是初始化ip的类,一个是和前端交互的类 8 4、首先创建初始化ip这个类,并且继承方法,传入两个参数,第一让这个ip不能为空,第二添加列表,并且让这个列表添加错误信息 9 5、初始化正则表达式,分别初始化错误信息,初始化列表,并且让这个列表可以自定义,初始化错误信息,初始化匹配是否成功,初始化匹配成功之后的值 10 6、在方法类中遍历ip类的初始化方法,然后让前端的ip和后端的对应,然后执行正则表达式类中的方法,并且传入参数分别是字段的名字IP,和用户输入的内容,分别判断,如果用户可以输入为空,那么就判断匹配,匹配成功后的值为用户输入的内容,如果不能输入为空,那么要进行下面的判断,如果用户输入为空的时候,和用户输入不为空的时候,如果用户输入为空那么直接就判断输入错误。如果用户输入内容不为空,那么就要和正则表达式进行比较,如果比较正确,那么就匹配成功,传入用户输入的值,如果正则表达式比对不成功,那么就报错 11 7、在方法这个类中定义两个字典,把匹配成功和不成功的值分别封装到两个不同的列表中 12 8、在post方法中定义和前端模板语言的结合,判断如果出错就传入到前端的模板语言中,如果正确就不用传输
#/usr/bin/env python import tornado.ioloop import tornado.web import re class IPFiled: REGULAR="^(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}$" #required=True表示必须要填值,error_dict=None自定义用户显示的错误 def __init__(self,error_dict=None,required=True): self.error_dict={} #如果与定义错误不是空的,那么就与定义的错误信息更新到这里面,封装了错误信息, #注意这里的error_dict和self.error_dict是不一样的 if error_dict: self.error_dict.update(error_dict) self.required=required #错误信息 self.error=None #匹配成功的值是多少 self.value=None #是否匹配 self.is_valid=False def validata(self,name,input_value): """ :param name:字段的名字(这里为ip) :param input_value:input_value代表用户输入的值 :return: """ #如果用户输入可以为空 if not self.required: self.is_valid=True self.value=input_value #如果不可以允许用户输入为空 else: #如果用户输入的为空 if not input_value.strip(): #如果能获取到错误信息,在错误信息字典中,那么就输出错误信息 if self.error_dict.get("required",None): self.error=self.error_dict["required"] else: #如果没有填写错误信息,字典中没有错误信息 self.error="%s is required"%name #如果用户输入的内容不为空,那么就用正则表达式匹配 else: ret=re.match(IPFiled.REGULAR,input_value) #如果用户输入的内容正确 if ret: #匹配成功 self.is_valid=True self.value=input_value #这里的ret.group()=input_value else: #如果用户输入的内容是错误的 if self.error_dict.get("valid",None): self.error=self.error_dict["valid"] else: self.error="%s is invalid"% name class BaseForm: def check_valid(self, handler): flag=True #创建一个字段 value_dict={} error_message_dict={} success_value_dict={} #下面for循环遍历的是IPFile #这里regular代指IPFiled对象,也就是错误信息(执行__init__),这里遍历的就是后台ip等 for key,regular in self.__dict__.items(): #key:ip。。。 #handler:HomeHandler对象,self.get...self.前端对象 ip等 #regular:IPFiled(required=True) #input_value=用户输入的值 input_value=handler.get_argument(key) #这里代表IPFiled对象.validata(),将具体的验证放到了对象中, regular.validata(key,input_value) #判断如果匹配了 if regular.is_valid: #把成功的值放入到这个字典中 success_value_dict[key]=regular.value else: #把错误信息放到这个字典中 error_message_dict[key]=regular.error flag=False value_dict[key]=input_value return flag,success_value_dict,error_message_dict class HomeForm(BaseForm): def __init__(self): #这里required=True表示这个ip输入不能为空,error_dict是自己加的错误信息,优先级要比默认的高 self.ip = IPFiled(required=True,error_dict={"required":"别闹,别整空的","valid":"兄弟,格式错误了"}) class HomeHandler(tornado.web.RequestHandler): def get(self, *args, **kwargs): self.render("home.html",error_dict=None) def post(self, *args, **kwargs): obj=HomeForm() is_valid,success_dict,error_dict=obj.check_valid(self) #这里的is_valid就是flag,如果flag为true那么就成功,否则就出现错误信息 if is_valid: print("success",success_dict) else: print("error",error_dict) self.render("home.html",error_dict=error_dict) # class MainForm(BaseForm): # def __init__(self): # self.host = "(.*)" # self.ip = "^(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}$" # self.port = '(\d+)' # self.phone = '^1[3|4|5|8][0-9]\d{8}$' # class MainHandler(tornado.web.RequestHandler): # def get(self): # self.render("index.html") # def post(self, *args, **kwargs): # obj=MainForm() # #获取用户输入的内容,和正则表达式匹配,self指代前端host,ip等,这里是把后端的host和ip传入和前端的host对应 # #由于方法中有两个返回值,所以这里要定义两个 # is_valid,value_dict=obj.check_valid(self) # print(is_valid) # #如果全部验证成功,那么将用户输入的所有内容全部放到字典中 # if is_valid: # print(value_dict) settings={ "template_path":"views", } application = tornado.web.Application([ # (r"/index", MainHandler), (r"/home",HomeHandler), ],**settings) if __name__ == "__main__": # 下面是创建了socket,循环,以及epoll io多路复用 socket运行起来 application.listen(8002) tornado.ioloop.IOLoop.instance().start()
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> </head> <body> <form action="/home" method="post" > <input type="text" name="ip" placeholder="ip"/> {% if error_dict %} <span>{{error_dict['ip']}}</span> {% end %} <input type="submit"/> </form> </body> </html>
添加host
一、创建post类
要把host等写入里面只需要在python代码中添加创建正则表达式类,其实就是更改一下正则表达式就可以了
class StringFiled: REGULAR="^(.*)$" #required=True表示必须要填值,error_dict=None自定义用户显示的错误 def __init__(self,error_dict=None,required=True): self.error_dict={} #如果与定义错误不是空的,那么就与定义的错误信息更新到这里面,封装了错误信息, #注意这里的error_dict和self.error_dict是不一样的 if error_dict: self.error_dict.update(error_dict) self.required=required #错误信息 self.error=None #匹配成功的值是多少 self.value=None #是否匹配
二、在主类中添加这个创建类中的对象
class HomeForm(BaseForm): def __init__(self): #这里required=True表示这个ip输入不能为空,error_dict是自己加的错误信息,优先级要比默认的高 self.ip = IPFiled(required=True,error_dict={"required":"别闹,别整空的","valid":"兄弟,格式错误了"}) self.host=StringFiled(required=False)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> </head> <body> <form action="/home" method="post" > <input type="text" name="ip" placeholder="ip"/> <input type="text" name="host" placeholder="host"/> {% if error_dict %} <span>{{error_dict['ip']}}</span> {% end %} <input type="submit"/> </form> </body> </html>
关于checkbox的form提交
一、创建一个checkbox类,注意这里只需要判断用户选中和没选中的问题
class CheckBoxFiled: def __init__(self,error_dict=None,required=True): self.error_dict={} #如果与定义错误不是空的,那么就与定义的错误信息更新到这里面,封装了错误信息, #注意这里的error_dict和self.error_dict是不一样的 if error_dict: self.error_dict.update(error_dict) self.required=required #错误信息 self.error=None #匹配成功的值是多少 self.value=None #是否匹配 self.is_valid=False def validata(self,name,input_value): """ :param name:字段的名字(这里为favor) :param input_value:input_value用户选中的内容[1,2] :return: 已经确定用户的内容是一个列表或者None """ #如果允许为空 if not self.required: self.is_valid=True self.value=input_value #如果不可以允许用户输入为空 else: #如果用户不允许为空 if not input_value: if self.error_dict.get("required",None): self.error=self.error_dict["required"] else: self.error="%s is required"%name else: #如果用户选中 self.is_valid=True self.value=input_value
二、方法中判断字段是否是checkboxFiled对象,这里get_arguments()方法中没有默认参数
class BaseForm: def check_valid(self, handler): flag=True #创建一个字段 value_dict={} error_message_dict={} success_value_dict={} #下面for循环遍历的是IPFile #这里regular代指IPFiled对象,也就是错误信息(执行__init__),这里遍历的就是后台ip等 for key,regular in self.__dict__.items(): if type(regular)==CheckBoxFiled: #注意get_arguments没有默认参数 input_value=handler.get_arguments(key) else: input_value=handler.get_argument(key) #这里代表IPFiled对象.validata(),将具体的验证放到了对象中, regular.validata(key,input_value) #判断如果匹配了 if regular.is_valid: #把成功的值放入到这个字典中 success_value_dict[key]=regular.value else: #把错误信息放到这个字典中 error_message_dict[key]=regular.error flag=False value_dict[key]=input_value return flag,success_value_dict,error_message_dict
第三步添加checkbox类对象
class HomeForm(BaseForm): def __init__(self): #这里required=True表示这个ip输入不能为空,error_dict是自己加的错误信息,优先级要比默认的高 self.ip = IPFiled(required=True,error_dict={"required":"别闹,别整空的","valid":"兄弟,格式错误了"}) self.host=StringFiled(required=False) self.favor=CheckBoxFiled(required=True)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> </head> <body> <form action="/home" method="post" > <input type="text" name="ip" placeholder="ip"/> <input type="text" name="host" placeholder="host"/> <p> <input type="checkbox" name="favor" value="1"/>篮球; <input type="checkbox" name="favor" value="2"/>足球; <input type="checkbox" name="favor" value="3">玻璃球; </p> {% if error_dict %} <span>{{error_dict['ip']}}</span> {% end %} <input type="submit"/> </form> </body> </html>
上传文件
1 1、 创建上传文件这个类。在类进行正则表达式的判断 2 2、 创建这个类的对象 self.fafafa=FileFile(required=True) 3 3、 执行check_valid方法,判断regular如果 是上传这个类,那么首先获取上传的文件,,这里的key代指的是字段,
handler.request.files.get(key),由于文件存储的模式是[{“body”:”xx”,”filename”:”xx”}],遍历能得到文件里面
的字典,也就能得到文件名 4 4、 把字段和文件名传入到类中,执行类中的方法 ,进行判断上传的文件是否符合要求,并且把这些传入到前端 5 5、 执行save方法,把上传的文件存储在后台
#/usr/bin/env python import tornado.ioloop import tornado.web import re import os class FileFiled: REGULAR="^(\w+\.pdf)|(\w+\.mp3)|(\w+\.py)$" def __init__(self,error_dict=None,required=True): self.error_dict={} #如果与定义错误不是空的,那么就与定义的错误信息更新到这里面,封装了错误信息, #注意这里的error_dict和self.error_dict是不一样的 if error_dict: self.error_dict.update(error_dict) self.required=required #错误信息 self.error=None #匹配成功的值是多少 self.value=[] #是否匹配,这里默认是匹配的 self.is_valid=True # self.name=None self.success_file_name=[] def validata(self,name,all_file_name_list): """ :param name:字段名 :param all_file_name_list: 所有文件的文件名 :return: """ self.name=name #如果可以允许用户不上传 if not self.required: self.is_valid=True #表示所有合法的地址 self.value=all_file_name_list #如果不可以允许用户输入为空 else: #如果允许用户上传但是用户没有上传 if not all_file_name_list: self.is_valid=False if self.error_dict.get("required",None): self.error=self.error_dict["required"] else: self.error="%s is required"%name else: for file_name in all_file_name_list: ret=re.match(FileFiled.REGULAR,file_name) if not ret: self.is_valid=False if self.error_dict.get("valid",None): self.error_dict=self.error_dict["valid"] else: self.error="%s is invalid "% name break else: self.value.append(file_name) def save(self,request,path="statics"): #获取所有文件列表 file_metas=request.files.get(self.name) #循环文件列表 for meta in file_metas: #每一个文件的文件名 file_name=meta["filename"] #创建路径 new_file_name=os.path.join(path,file_name) #判断每个文件不为空并且符合规则 if file_name and file_name in self.value: with open(new_file_name,"wb") as up: up.write(meta["body"]) class BaseForm: def check_valid(self, handler): flag=True #创建一个字段 value_dict={} error_message_dict={} success_value_dict={} #下面for循环遍历的是IPFile #这里regular代指IPFiled对象,也就是错误信息(执行__init__),这里遍历的就是后台ip等 for key,regular in self.__dict__.items(): if type(regular)==FileFiled: #获取文件中的key file_list=handler.request.files.get(key) #获取的文件里面存放的是字典[{"body":xx,"filename":"xx"}] input_valu=[] #获取文件名 for i in file_list: input_valu.append(i["filename"]) #这里是吧获取的文件名全部传递到FileFile类中进行验证 regular.validata(key,input_valu) #判断如果匹配了 if regular.is_valid: #把成功的值放入到这个字典中 success_value_dict[key]=regular.value else: error_message_dict[key]=regular.error flag=False value_dict[key]=input_valu return flag,success_value_dict,error_message_dict class HomeForm(BaseForm): def __init__(self): self.fafafa=FileFiled(required=True) class HomeHandler(tornado.web.RequestHandler): def get(self, *args, **kwargs): self.render("home.html",error_dict=None) def post(self, *args, **kwargs): #这里self.request是内部所有的文件,这里是获取内部提交的文件 # file=self.request.files.get("fafafa",[]) obj=HomeForm() is_valid,success_dict,error_dict=obj.check_valid(self) #这里的is_valid就是flag,如果flag为true那么就成功,否则就出现错误信息 if is_valid: print("success",success_dict) obj.fafafa.save(self,request) else: print("error",error_dict) self.render("home.html",error_dict=error_dict) settings={ "template_path":"views", } application = tornado.web.Application([ # (r"/index", MainHandler), (r"/home",HomeHandler), ],**settings) if __name__ == "__main__": # 下面是创建了socket,循环,以及epoll io多路复用 socket运行起来 application.listen(8003) tornado.ioloop.IOLoop.instance().start()
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> </head> <body> <form action="/home" method="post" > <input type="text" name="ip" placeholder="ip"/> <input type="text" name="host" placeholder="host"/> <p> <input type="checkbox" name="favor" value="1"/>篮球; <input type="checkbox" name="favor" value="2"/>足球; <input type="checkbox" name="favor" value="3">玻璃球; </p> <p> <input type="file" name="fafafa"/> <input type="file" name="fafafa"/> </p> {% if error_dict %} <span>{{error_dict['ip']}}</span> {% end %} <input type="submit"/> </form>
欢迎拍砖