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()
python代码
<!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>
home.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
        #是否匹配
View Code

二、在主类中添加这个创建类中的对象

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)
View Code
<!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>
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
View Code

二、方法中判断字段是否是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
View Code

第三步添加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)
View Code
<!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>
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()
View Code
<!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>
HTML代码

           欢迎拍砖 

posted @ 2017-04-16 18:37  pi-pi-miao-miao  阅读(989)  评论(0编辑  收藏  举报