form表单提交数据时,获取提交数据的同时,还需要进行数据规范性的验证,

一、关于input标签中text\password的验证

(一)基本方式

1、设置一个类专门用于form验证,

2、验证类的init函数中,预置好用于验证的正则规范,

3、验证类中定义验证方法,提取用户提交数据,与正则规范比对,

#!/usr/bin/env python
# -*- coding:utf-8 -*-

import tornado.ioloop
import tornado.web

class BaseForm:
    def check_valid(self,handler):
        import re
        flag = True                                 # 标记提交的数据是否通过验证
        value_dict = {}                             # form提交数据
        for key,regular in self.__dict__.items():
            input_value = handler.get_argument(key)
            val = re.match(regular,input_value)
            if not val:
               flag = False
            value_dict[key] = input_value
        return flag,value_dict

class IndexForm(BaseForm):
    def __init__(self):
        self.host = '(.*)'
        self.ip = '(\d+)'
        self.tel = '^1[3|4|5|8][0-9]\d{8}$'

class LoginForm(BaseForm):
    def __init__(self):
        self.user = '^[a-zA-Z0-9_-]{4,16}$'
        self.pwd = '^.*(?=.{6,})(?=.*\d)(?=.*[A-Z])(?=.*[a-z])(?=.*[!@#$%^&*? ]).*$'
        self.email = '^([A-Za-z0-9_\-\.])+\@([A-Za-z0-9_\-\.])+\.([A-Za-z]{2,4})$'


class IndexHandler(tornado.web.RequestHandler):
    def get(self):
        self.render('index.html')
    def post(self, *args, **kwargs):
        obj = IndexForm()                               # 创建form验证对象
        flag,value_dict = obj.check_valid(self)         # 开始form验证,
        print(flag,value_dict)

class LoginHandler(tornado.web.RequestHandler):
    def get(self):
        self.render('login.html')
    def post(self, *args, **kwargs):
        obj = LoginForm()
        flag,value_dict = obj.check_valid(self)
        print(flag,value_dict)


# 路径解析
settings = {
    "template_path":"views",
    "static_path":"statics",
    "static_url_prefix":"/sss/",
}

# 二级路由,先匹配域名,
application = tornado.web.Application([
    (r"/index",IndexHandler),
    (r"/login",LoginHandler),
],**settings)


# 开启服务器,监听
if __name__ == "__main__":
    application.listen(8001)
    tornado.ioloop.IOLoop.instance().start()
fromCheck_index.py
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>login</title>
</head>
<body>
    <form action="/login" method="post">
        <input type="text" name="user" placeholder="name" />
        <input type="text" name="pwd" placeholder="password" />
        <input type="text" name="email" placeholder="e_mail" />
        <input type="submit" value="submit" />
    </form>
</body>
</html>
login.html
<!DOCTYPE html>

<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>index</title>
    <script src="sss/jquery-1.12.4.min.js"></script>
    <style>
        input{margin:10px 10px;}
    </style>
</head>
<body>
    <form action="/index" method="post">
        <input type="text" name="host" placeholder="host" />
        <input type="text" name="ip" placeholder="ip" />
        <input type="text" name="tel" placeholder="mobile phone" />
        <input type="submit" value="submit" />
    </form>
</body>
</html>
index.html

(二)优化版本

解决问题:1、有的输入值可以为空,2、输入值错误时提示,

#!/usr/bin/env python
# -*- coding:utf-8 -*-

import tornado.ioloop
import tornado.web
import re

# ----------------------------------------------------------------------------------#
class BaseTextFiled:
    def __init__(self,required=True,error_dict=None):
        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 validate(self,name,input_value):
        '''
        单独项验证的具体操作
        :param name: 需要进行验证的参数名
        :param 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 can not be empty !" % name
            else:                                                   # 用户输入不为空,
                ret= re.match(self.REGULAR,input_value)
                if ret:                                                 # 如果格式正确,保存相应的数值
                    self.is_valid = True
                    self.value = input_value
                else:                                                   # 如果格式错误,提示格式错误信息
                    if self.error_dict.get('valid',None):
                        self.error = self.error_dict['valid']
                    else:
                        self.error = "%s is invalid !" % name

class USERfiled(BaseTextFiled):
    # 4到16位(字母,数字,下划线,减号)
    REGULAR = '^[a-zA-Z0-9_-]{4,16}$'

class PWDfiled(BaseTextFiled):
    # 最少6位,包括至少1个大写字母,1个小写字母,1个数字,1个特殊字符
    REGULAR = '^.*(?=.{6,})(?=.*\d)(?=.*[A-Z])(?=.*[a-z])(?=.*[!@#$%^&*? ]).*$'

class Emailfiled(BaseTextFiled):
    REGULAR = '^([A-Za-z0-9_\-\.])+\@([A-Za-z0-9_\-\.])+\.([A-Za-z]{2,4})$'

class QQfiled(BaseTextFiled):
    # 5至11位数字
    REGULAR = '^[1-9][0-9]{4,10}$'

class PersonIDfiled(BaseTextFiled):
    # 身份证号(18位)
    REGULAR = '^[1-9]\d{5}(18|19|([23]\d))\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$'

class TELfiled(BaseTextFiled):
    # 11位手机号码
    REGULAR = '^1[3|4|5|8][0-9]\d{8}$'

class IPfiled(BaseTextFiled):
    # ipv4地址正则
    REGULAR = '^(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}$'

class POSTfiled(BaseTextFiled):
    # 端口号
    REGULAR = '(\d+)'

class HOSTfiled(BaseTextFiled):
    # 主机号
    REGULAR = '(.*)'

# ----------------------------------------------------------------------------------#
class BaseForm:
    def check_valid(self,handler):
        '''
        对form提交的整体进行验证
        :param handler: 待验证的form句柄
        :return: flag:验证通过标识、
                  error_message_dict:错误提示信息、
                  success_value_dict:输入的正确信息
        '''
        flag = True
        error_message_dict = {}
        success_value_dict = {}
        for key,regular in self.__dict__.items():            # 对表单进行逐项验证
            input_value = handler.get_argument(key)
            regular.validate(key,input_value)                 # 具体验证方法
            if regular.is_valid:
                success_value_dict[key] = regular.value
                error_message_dict[key] = ""
            else:
                error_message_dict[key] = regular.error
                flag = False
        return flag,error_message_dict,success_value_dict

class IndexForm(BaseForm):
    def __init__(self):
        self.host = HOSTfiled(required = True)
        self.ip = IPfiled(required = True)
        self.post = POSTfiled(required = True)

class LoginForm(BaseForm):
    def __init__(self):
        self.user = USERfiled(required = True,error_dict={'required':'不能为空','valid':'格式错误'})
        self.pwd = PWDfiled(required = True,error_dict={'required':'不能为空','valid':'格式错误'})
        self.email = Emailfiled(required = False)
        self.tel = TELfiled(required = True,error_dict={'required':'不能为空','valid':'格式错误'})
        self.qq = QQfiled(required = False)
        self.personID = PersonIDfiled(required = True,error_dict={'required':'不能为空','valid':'格式错误'})

# ----------------------------------------------------------------------------------#
class IndexHandler(tornado.web.RequestHandler):
    def get(self):
        self.render('index.html')
    def post(self, *args, **kwargs):
        obj = IndexForm()                                                          # 创建form验证对象
        flag,error_message_dict,success_value_dict = obj.check_valid(self)         # 开始form验证,
        print(flag,error_message_dict,success_value_dict)

class LoginHandler(tornado.web.RequestHandler):
    def get(self):
        self.render('login.html',error_dict = None)
    def post(self, *args, **kwargs):
        obj = LoginForm()
        flag,error_message_dict,success_value_dict = obj.check_valid(self)
        if flag:
            self.write('is ok')
        else:
            self.render('login.html',error_dict = error_message_dict)


# 路径解析
settings = {
    "template_path":"views",
    "static_path":"statics",
    "static_url_prefix":"/sss/",
}

# 二级路由,先匹配域名,
application = tornado.web.Application([
    (r"/index",IndexHandler),
    (r"/login",LoginHandler),
],**settings)


# 开启服务器,监听
if __name__ == "__main__":
    application.listen(8001)
    tornado.ioloop.IOLoop.instance().start()
index.py
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>login</title>
    <style>
        input{margin:10px 10px}
        .red{border:1px solid pink;}
    </style>
</head>
<body>
    <form action="/login" method="post">
        <input type="text" name="user" placeholder="name" class="red"  />
        {% if error_dict %}
        <span>{{error_dict['user']}}</span>
        {% end %}
        <br>

        <input type="password" name="pwd" placeholder="password" class="red" />
        {% if error_dict %}
        <span>{{error_dict['pwd']}}</span>
        {% end %}
        <br>

        <input type="text" name="email" placeholder="e_mail" />
        {% if error_dict %}
        <span>{{error_dict['email']}}</span>
        {% end %}
        <br>

        <input type="text" name="tel" placeholder="mobile phone" class="red" />
        {% if error_dict %}
        <span>{{error_dict['tel']}}</span>
        {% end %}
        <br>

        <input type="text" name="qq" placeholder="qq" />
        {% if error_dict %}
        <span>{{error_dict['qq']}}</span>
        {% end %}
        <br>

        <input type="text" name="personID" placeholder="personID" class="red"/>
        {% if error_dict %}
        <span>{{error_dict['personID']}}</span>
        {% end %}
        <br>

        <input type="submit" value="submit" />
    </form>
</body>
</html>
login.html
<!DOCTYPE html>

<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>index</title>
    <script src="sss/jquery-1.12.4.min.js"></script>
    <style>
        input{margin:10px 10px;}
    </style>
</head>
<body>
    <form action="/index" method="post">
        <input type="text" name="host" placeholder="host" />
        <input type="text" name="ip" placeholder="ip" />
        <input type="text" name="post" placeholder="post" />
        <input type="submit" value="submit" />
    </form>
</body>
</html>
index.html

注意:form表单提交的数据和验证的数据名称需要保持一致,


 二、关于form中的checkbox验证 

与text\password的验证有些许不同,具体如下:

1、获取CheckBox提交数据,使用语句self.get_arguments,

2、checkbox的验证不需要正则,只需要判断是否传值就行,


三、form上传文件的验证

验证上传文件,首先验证文件名称是否合法,如果名称合法,可设置自动上传文件,

1、获取上传文件的文件名称列表,

由于上传文件以name为单位、以列表形式存在,所以同一个name下面可以有多个文件,

2、验证文件名称是否合法,

    

3、名称合法后,可设置自动上传文件到指定url


 

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>login</title>
    <style>
        input{margin:10px 10px}
        .red{border:1px solid pink;}
    </style>
</head>
<body>
    <form action="/login" method="post" enctype="multipart/form-data">
        <input type="text" name="user" placeholder="name" class="red"  />
        {% if error_dict %}
        <span>{{error_dict['user']}}</span>
        {% end %}
        <br>

        <input type="password" name="pwd" placeholder="password" />
        {% if error_dict %}
        <span>{{error_dict['pwd']}}</span>
        {% end %}
        <br>

        <input type="text" name="email" placeholder="e_mail" />
        {% if error_dict %}
        <span>{{error_dict['email']}}</span>
        {% end %}
        <br>

        <input type="text" name="tel" placeholder="mobile phone" class="red" />
        {% if error_dict %}
        <span>{{error_dict['tel']}}</span>
        {% end %}
        <br>

        <input type="text" name="qq" placeholder="qq" />
        {% if error_dict %}
        <span>{{error_dict['qq']}}</span>
        {% end %}
        <br>

        <input type="text" name="personID" placeholder="personID" class="red"/>
        {% if error_dict %}
        <span>{{error_dict['personID']}}</span>
        {% end %}
        <br><br>


        <span>爱好:</span><br>
        <span>足球</span><input type="checkbox" value="1" name="favor">
        <span>篮球</span><input type="checkbox" value="2" name="favor">
        <span>乒乓球</span><input type="checkbox" value="3" name="favor">
        <span>羽毛球</span><input type="checkbox" value="4" name="favor">
        {% if error_dict %}
        <span>{{error_dict['favor']}}</span>
        {% end %}
        <br><br>

        <span>性别:</span><br>
        <span></span><input type="radio" value="1" name="sex" />
        <span></span><input type="radio" value="0" name="sex" />
        {% if error_dict %}
        <span>{{error_dict['sex']}}</span>
        {% end %}
        <br><br>

        <textarea name="balabala" class="red" style="height:50px;width:500px;" placeholder="想说些什么..."></textarea>
        {% if error_dict %}
        <span>{{error_dict['balabala']}}</span>
        {% end %}
        <br><br>

        <input type="file" name="myPic" />
        <input type="file" name="myPic" />
        {% if error_dict %}
        <span>{{error_dict['myPic']}}</span>
        {% end %}
        <br><br>

        <input type="submit" value="submit" />
    </form>
</body>
</html>
login

 

#!/usr/bin/env python
# -*- coding:utf-8 -*-

import tornado.ioloop
import tornado.web
import re
import os

# ----------------------------------------------------------------------------------#
class BaseTextFiled:
    def __init__(self,required=True,error_dict=None):
        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 validate(self,name,input_value):
        '''
        单独项验证的具体操作
        :param name: 需要进行验证的参数名
        :param 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 can not be empty !" % name
            else:                                                   # 用户输入不为空,
                ret= re.match(self.REGULAR,input_value)
                if ret:                                                 # 如果格式正确,保存相应的数值
                    self.is_valid = True
                    self.value = input_value
                else:                                                   # 如果格式错误,提示格式错误信息
                    if self.error_dict.get('valid',None):
                        self.error = self.error_dict['valid']
                    else:
                        self.error = "%s is invalid !" % name

class USERfiled(BaseTextFiled):
    # 4到16位(字母,数字,下划线,减号)
    REGULAR = '^[a-zA-Z0-9_-]{4,16}$'

class PWDfiled(BaseTextFiled):
    # 最少6位,包括至少1个大写字母,1个小写字母,1个数字,1个特殊字符
    REGULAR = '^.*(?=.{6,})(?=.*\d)(?=.*[A-Z])(?=.*[a-z])(?=.*[!@#$%^&*? ]).*$'

class Emailfiled(BaseTextFiled):
    REGULAR = '^([A-Za-z0-9_\-\.])+\@([A-Za-z0-9_\-\.])+\.([A-Za-z]{2,4})$'

class QQfiled(BaseTextFiled):
    # 5至11位数字
    REGULAR = '^[1-9][0-9]{4,10}$'

class PersonIDfiled(BaseTextFiled):
    # 身份证号(18位)
    REGULAR = '^[1-9]\d{5}(18|19|([23]\d))\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$'

class TELfiled(BaseTextFiled):
    # 11位手机号码
    REGULAR = '^1[3|4|5|8][0-9]\d{8}$'

class IPfiled(BaseTextFiled):
    # ipv4地址正则
    REGULAR = '^(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}$'

class POSTfiled(BaseTextFiled):
    # 端口号
    REGULAR = '(\d+)'

class HOSTfiled(BaseTextFiled):
    # 主机号
    REGULAR = '(.*)'

class BALABALAfiled(BaseTextFiled):
    # 最多200个字符
    REGULAR = '^[\s\S]{,200}$'

# ----------------------------------------------------------------------------------#
class CHOICEfiled(BaseTextFiled):
    def validate(self,name,input_value):
        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 can not be empty !" % name
            else:
                self.is_valid = True
                self.value = input_value

# ----------------------------------------------------------------------------------#
class UPLOADfiled(BaseTextFiled):
    # 接收文件格式:pdf、img、py
    REGULAR = '^(\w+\.pdf)|(\w+\.img)|(\w+\.py)$'

    def validate(self,name,all_files_name_list):
        self.name = name    # 用于文件save函数调用
        self.is_valid = True
        if not self.required:                                   # 用户输入可以为空
            self.value = all_files_name_list
        else:                                                   # 用户输入不可以为空
            if not all_files_name_list:
                self.is_valid = False
                if self.error_dict.get('required',None):
                    self.error = self.error_dict['required']
                else:
                    self.error = "%s can not be empty !" % name
            else:
                # 上传文件名称验证
                self.value = []
                for each_file_name in all_files_name_list:       # 验证文件名字列表,有一个不符合要求,就验证失败
                    ret= re.match(self.REGULAR,each_file_name)
                    if ret:
                        self.value.append(each_file_name)
                    else:
                        self.is_valid = False
                        if self.error_dict.get('valid',None):
                            self.error = self.error_dict['valid']
                        else:
                            self.error = "%s is invalid !" % name
                        break

    def save(self,request,path='statics/img'):
        # 全部验证成功后,上传文件
        file_metas = request.files.get(self.name,[])
        for meta in file_metas:
            fileName = os.path.join(path,meta['filename'])
            if fileName and fileName in self.value:
                with open(fileName,'wb') as upFile:
                    upFile.write(meta['body'])
# ----------------------------------------------------------------------------------#

class BaseForm:
    def check_valid(self,handler):
        '''
        对form提交的整体进行验证
        :param handler: 待验证的form句柄
        :return: flag:验证通过标识、
                  error_message_dict:错误提示信息、
                  success_value_dict:输入的正确信息
        '''
        flag = True
        error_message_dict = {}
        success_value_dict = {}
        for key,regular in self.__dict__.items():            # 对表单进行逐项验证
            if type(regular) == CHOICEfiled:
                input_value = handler.get_arguments(key)
            elif type(regular) == UPLOADfiled:
                input_value = []
                if handler.request.files.get('myPic',[]):
                    file_metas = handler.request.files['myPic']
                    for meta in file_metas:
                        fileName = meta['filename']
                        input_value.append(fileName)
            else:
                input_value = handler.get_argument(key)

            regular.validate(key,input_value)                 # 具体验证方法
            if regular.is_valid:
                success_value_dict[key] = regular.value
                error_message_dict[key] = ""
            else:
                error_message_dict[key] = regular.error
                flag = False
        return flag,error_message_dict,success_value_dict

class IndexForm(BaseForm):
    def __init__(self):
        self.host = HOSTfiled(required = True)
        self.ip = IPfiled(required = True)
        self.post = POSTfiled(required = True)
        self.favor = FAVORfiled(required = True)

class LoginForm(BaseForm):
    def __init__(self):
        self.user = USERfiled(required = True,error_dict={'required':'不能为空','valid':'格式错误'})
        self.pwd = PWDfiled(required = False)
        self.email = Emailfiled(required = False)
        self.tel = TELfiled(required = True,error_dict={'required':'不能为空','valid':'格式错误'})
        self.qq = QQfiled(required = False)
        self.personID = PersonIDfiled(required = True,error_dict={'required':'不能为空','valid':'格式错误'})
        self.favor = CHOICEfiled(required = True,error_dict={'required':'请选择'})
        self.sex = CHOICEfiled(required = True,error_dict={'required':'请选择'})
        self.balabala = BALABALAfiled(required = True,error_dict={'required':'不能为空','valid':'不超过200个字符'})
        self.myPic = UPLOADfiled(required = True,error_dict={'required':'请上传文件','valid':'仅接收如下格式的文件:pdf、img、py'})

# ----------------------------------------------------------------------------------#
class IndexHandler(tornado.web.RequestHandler):
    def get(self):
        self.render('index.html')

    def post(self, *args, **kwargs):
        obj = IndexForm()                                                          # 创建form验证对象
        flag,error_message_dict,success_value_dict = obj.check_valid(self)         # 开始form验证,
        print(flag,error_message_dict,success_value_dict)

class LoginHandler(tornado.web.RequestHandler):
    def get(self):
        self.render('login.html',error_dict = None)

    def post(self, *args, **kwargs):
        obj = LoginForm()
        flag,error_message_dict,success_value_dict = obj.check_valid(self)
        if flag:
            obj.myPic.save(self.request,path='statics/img')  # 自动上传文件
            print('1',flag,error_message_dict,success_value_dict)
            self.write('is ok')
        else:
            self.render('login.html',error_dict = error_message_dict)


# 路径解析
settings = {
    "template_path":"views",
    "static_path":"statics",
    "static_url_prefix":"/sss/",
}

# 二级路由,先匹配域名,
application = tornado.web.Application([
    (r"/index",IndexHandler),
    (r"/login",LoginHandler),
],**settings)


# 开启服务器,监听
if __name__ == "__main__":
    application.listen(8001)
    tornado.ioloop.IOLoop.instance().start()
index