看用Tornado如何自定义实现表单验证
我们知道,平时在登陆某个网站或软件时,网站对于你输入的内容是有要求的,并且会对你输入的错误内容有提示,对于Django这种大而全的web框架,是提供了form表单验证功能,但是对于Tornado而言,就没有这功能,所以就需要我们来自己自定义form表单验证,而且这种方法正是Django里的form表单验证的实质内容,也帮我们在后面学习Django理解相关的源码。
写之前,我们必须知道form表单验证的实质是什么?
实质就是正则匹配
我们知道用户提交数据是通过post方式提交,所以我们重写post方法,并在post方法进行业务逻辑处理
- 获取用户提交的数据
- 将用户提交的数据和正则表达式匹配
第一阶段
- 场景:我们知道后台是一个url对应一个类来处理客户请求的
- 问题:那么在不同页面里会相同需求,比如登陆时用邮箱登陆,修改密码时又要用邮箱,那对于这样同样验证需求,在我们的后台是不是代码就重复了呢?
- 解决:独立一个模块专门用于用户信息验证
我们先看一下下面这段代码
class MainForm(object):
def __init__(self):
# 各种信息正则匹配规则
# 并且要求这里字段名和前端传来的name一致
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, request):
flag = True
form_dict = self.__dict__ #获取类的普通字段和值
for key, regular in form_dict.items():
post_value = request.get_argument(key) #获取用户输入的值
# 让提交的数据 和 定义的正则表达式进行匹配
ret = re.match(regular, post_value)
print key,ret,post_value
if not ret:
flag = False #一旦有匹配不成功的,设置为False
return flag #post方法里根据这个返回值来决定给客户返回什么内容
从上面我们可以知道,这个模块只是简简单单的给了true or false返回值的问题,我们还希望返回客户输入的值,看下怎么优化吧
- 在check_vaild方法里定义一个局部变量-字典,然后接收客户的信息,并把这个字典一并返回到post方法里
第二阶段
在上面,我们已经独立了一个模块来验证信息,但问题又来了,上面这个模块我定义的时候以index页面定制的,不同的页面处理的需要是不一样的,那如果解决这个问题,好像可以每个页面都独立一个模块,但这样,代码未免重复的太多了。
仔细的人会发现,其实就是init里需要匹配的内容不一样,下面的check_vaild方法都是一样的
类的继承,写一个BaseForm父类,让其他验证类继承
class BaseForm:
def check_valid(self, handle):
flag = True
value_dict = {}
for key, regular in self.__dict__.items():
# host,ip port phone
input_value = handle.get_argument(key)
val = re.match(regular, input_value)
print(key, input_value, val, regular)
if not val:
flag = False
value_dict[key] = input_value
return flag, value_dict class IndexForm(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 HomeForm(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}$"
在实际场景中,客户填写的信息有些是必填,有些是可不填,这样又增加了匹配的复杂度,我们可不可以把每种匹配规则独立成一个类,并达到后台传入True时,不为空,传入了False时可为空呢??并且我们让这个类处理时返回错误提示信息??
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}$" def __init__(self, error_dict=None, required=True):
self.error_dict = {} #用于自定制错误提醒信息
if error_dict:
self.error_dict.update(error_dict)
self.required = required #可空否
self.error = None #记录错误提醒信息
self.is_valid = False #匹配成功与否
self.value = None #用户发来进行匹配的值 def validate(self, name, input_value):
'''
:param name: 字段名:IP 方便在错误信息里提示
: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 is required" % name
else:
ret = re.match(IPFiled.REGULAR, input_value)
if ret:
#匹配成功--》通过
self.id_valid = True
self.value = ret.group()
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, handle):
flag = True
success_value_dict = {}
error_message_dict = {}
for key, regular in self.__dict__.items():
#key-->ip handle-->homeHandler对象 regular--》IPFiled对象
input_value = handle.get_argument(key) #用户输入的值
#将验证放在了IPFiled对象里
regular.validate(key,input_value)
if regular.is_valid:
#匹配成功就添加用户输入值
success_value_dict[key] = regular.value
else:
#添加错误提示信息
error_message_dict[key] = regular.error
flag = False
return flag, error_message_dict,success_value_dict class HomeForm(BaseForm):
def __init__(self):
self.ip = IPFiled(required=True,error_dict={"required":"别闹","valid":"妹子,格式错了"}) class HomeHandler(tornado.web.RequestHandler):
def get(self):
self.render('home.html') def post(self, *args, **kwargs):
obj = HomeForm()
# 获取用户输入的内容
# 和正则表达式匹配
is_valid,error_dict,success_dict = obj.check_valid(self)
print(is_valid)
if is_valid:
print(success_dict)
else:
print(error_dict)
第三阶段
在input类型有个叫checkbox的,在后台获取值不再是get_argument,而是get_arguments,不同于其他的input类型,所以在BaseForm的check_valid方法里获取值的方式就要改了,利用type进行判断
class BaseForm:
def check_valid(self, handle):
flag = True
error_message_dict = {}
success_value_dict = {}
for key, regular in self.__dict__.items():
# key: ip .....
# handle: HomeIndex对象,self.get_... self.
# regular: IPFiled(required=True) if type(regular) == ChechBoxFiled:
input_value = handle.get_arguments(key) #get_arguments是没有默认参数的
else:
input_value = handle.get_argument(key)
# input_value = 用户输入的值
# 将具体的验证,放在IPFiled对象中
regular.validate(key, input_value) if regular.is_valid:
success_value_dict[key] = regular.value
else:
error_message_dict[key] = regular.error
flag = False
另外对checkbox返回结果处理方式也稍微有些区别,不用对其合法性检测,只要判断是否为空即可,所以在CheckBoxFiled类的validate方法也要改
class CheckBoxFiled: def __init__(self, error_dict=None, required=True):
# 封装了错误信息
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: 字段名 favor
:param input_value: 用户表单中输入的内容,列表None or [1,2]
:return:
""" 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
第四阶段
除了checkbox这个特殊外,还有file----文件上传,在后台获取方式也不一样,不是self.get_argument,而是self.request.files.get(),得到的内容是一个列表,格式如 [{'body':'xx','filename':'xx'},{'body':'xx','filename':'xx'}],想要获得文件名,还要循环这个列表,通过filename的key取到,并且我们如果要把文件上传到服务端,就在FileFiled写入save方法,“body”里面就是文件内容
import tornado.ioloop
import tornado.web
import re
import os 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}$" def __init__(self, error_dict=None, required=True):
# 封装了错误信息
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 is required" % name
else:
ret = re.match(IPFiled.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 StringFiled:
REGULAR = "^(.*)$" def __init__(self, error_dict=None, required=True):
# 封装了错误信息
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 is required" % name
else:
ret = re.match(IPFiled.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 ChechBoxFiled: def __init__(self, error_dict=None, required=True):
# 封装了错误信息
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: 字段名 favor
:param input_value: 用户表单中输入的内容,列表None or [1,2]
:return:
""" 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 class FileFiled: REGULAR = "^(\w+\.pdf)|(\w+\.mp3)|(\w+\.py)$" def __init__(self, error_dict=None, required=True):
# 封装了错误信息
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_list = [] def validate(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 = self.error_dict['valid']
else:
self.error = "%s is invalid" % name
break
else:
self.value.append(file_name) #都匹配成功的文件名列表 def save(self, request, path='statics'):
# 所有文件列表
# request = HomeHandler.request self.name = fafafa(前端名字)
file_metas = request.files.get(self.name)
# 循环文件列表
temp_list = []
for meta in file_metas:
# 每一个文件的文件名
file_name = meta['filename']
# self.value:[1.py, 2.py] 【statics/1.py statics/2.py】
new_file_name = os.path.join(path, file_name)
#self.value--->success_file_name_list
if file_name and file_name in self.value:
temp_list.append(new_file_name)
with open(new_file_name, 'wb') as up:
up.write(meta['body'])
self.value = temp_list class BaseForm:
def check_valid(self, handle):
flag = True
error_message_dict = {}
success_value_dict = {}
for key, regular in self.__dict__.items():
# key: ip .....
# handle: HomeIndex对象,self.get_... self.
# regular: IPFiled(required=True) if type(regular) == ChechBoxFiled:
input_value = handle.get_arguments(key)
elif type(regular) == FileFiled:
# 获取文件名
file_list = handle.request.files.get(key)
# [{'body':'xx','filename':'xx'},{'body':'xx','filename':'xx'}]
input_value = [] #file_name_list
for item in file_list:
input_value.append(item['filename'])
# 所有文件名进行验证
else:
input_value = handle.get_argument(key)
# input_value = 用户输入的值
# 将具体的验证,放在IPFiled对象中
regular.validate(key, input_value) if regular.is_valid:
success_value_dict[key] = regular.value
else:
error_message_dict[key] = regular.error
flag = False return flag, success_value_dict, error_message_dict class HomeForm(BaseForm):
def __init__(self):
self.ip = IPFiled(required=True, error_dict={'required': "别闹,别整空的..", "valid": "骚年,格式错误了"})
self.host = StringFiled(required=False)
self.favor = ChechBoxFiled(required=True)
self.fafafa = FileFiled(required=True) #前端name同名fafafa class HomeHandler(tornado.web.RequestHandler):
def get(self):
self.render('home.html', error_dict=None) def post(self, *args, **kwargs): # self.get_argument()
# self.get_arguments()
# files = self.request.files.get('fafafa',[])
# # files = [ 文件一、文件二]
# print(type(files),files) obj = HomeForm()
is_valid, success_dict, error_dict = obj.check_valid(self)
if is_valid:
print('success',success_dict)
#只有全部通过,就执行上传方法
obj.fafafa.save(self.request) #HomeForm().fafafa=FileFiled()
else:
print('error', error_dict)
self.render('home.html', error_dict=error_dict) settings = {
'template_path': 'views',
'static_path': 'statics',
'static_url_prefix': '/statics/',
} application = tornado.web.Application([
(r"/home", HomeHandler),
], **settings) if __name__ == "__main__":
application.listen(8001)
tornado.ioloop.IOLoop.instance().start()
是不是有点乱,这么多类,好!这里画个小图,助于大家理解.....
是不是还是不好理解,好把,我画图有限...
看用Tornado如何自定义实现表单验证的更多相关文章
- tornado之自定义form表单验证
直接上链接吧:银角的地址 源码下载链接:点我点我点我...
- python26:自定义form表单验证
一.自定义Form的原理 1.1 各种form表单验证比较 只有python提供了form表单验证,其他的都没有提供.django提供的功能还不够强大.最强大的是微软的ASP.NET!我们可以自己写一 ...
- lumen手记:自定义Validate表单验证
版权声明:本文为博主原创文章,未经博主允许不得转载. 今天开始跳lumen的表单验证Validate类的坑,确实好坑!!! 首先,lumen的表单验证返回是无状态的json格式api,这... 所有开 ...
- web前端框架之自定义form表单验证
自定义form验证初试 .在后端创建一个类MainForm,并且在类中自定义host ip port phone等,然后写入方法,在post方法中创建MainForm对象,并且把post方法中的sel ...
- 【jQuery基础学习】06 jQuery表单验证插件-Validation
jQuery的基础部分前面都讲完了,那么就看插件了. 关于jQuery表单验证插件-Validation validation特点: 内置验证规则:拥有必填.数字.E-Mail.URL和信用卡号码等1 ...
- jquery validate强大的jquery表单验证插件
jquery validate的官方演示和文档地址: 官方网站:http://jqueryvalidation.org/ 官方演示:http://jqueryvalidation.org/files/ ...
- [php基础]PHP Form表单验证:PHP form validator使用说明
在PHP网站开发建设中,用户注册.留言是必不可少的功能,用户提交的信息数据都是通过Form表单提交,为了保证数据的完整性.安全性,PHP Form表单验证是过滤数据的首要环节,PHP对表单提交数据的验 ...
- ThinkPhp框架:父类及表单验证
这个知识点,就可以通过"登录"和"注册"的页面来学习这个知识点了首先先做一个"登录"功能一.登录功能(父类)(1)登录的控制器在我的控制器文 ...
- WPF权限控制——【3】数据库、自定义弹窗、表单验证
你相信"物竞天择,适者生存"这样的学说吗?但是我们今天却在提倡"尊老爱幼,救死扶伤",帮助并救护弱势群体:第二次世界大战期间,希特勒认为自己是优等民族,劣势民族 ...
随机推荐
- 安装VS2010 SP1后,再安装mvc3
安装VS2010 SP1后,再安装mvc3会报错,估计原因是此安装包会安装VS的补丁,而sp1的补丁版本高过此安装包的. AspNetMVC3ToolsUpdateSetup.exe 解决办法: 运行 ...
- 第三篇:python函数
1.python函数 函数是组织好的,可重复使用的,用来实现单一,或相关联功能的代码段. 函数能提高应用的模块性,和代码的重复利用率.你已经知道Python提供了许多内建函数,比如print().但你 ...
- poj2392 Space Elevator(多重背包问题)
Space Elevator Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 8569 Accepted: 4052 ...
- iOS开发多线程篇 08 —GCD的常见用法
iOS开发多线程篇—GCD的常见用法 一.延迟执行 1.介绍 iOS常见的延时执行有2种方式 (1)调用NSObject的方法 [self performSelector:@selector(run) ...
- C#中Equals和==的比较
一.值类型的比较 对于值类型来说 两者比较的都是”内容”是否相同,即 值 是否一样,很显然此时两者是划等号的. ; ; Console.WriteLine("i==j"+(i== ...
- jquerymobile动态添加元素之后
jquerymobile动态添加元素之后有些不能被正确渲染的解决方法:listview: 添加 jq(".detail").listview("refresh&quo ...
- SQL Server DTS向导,字段转换出现202和200错误
当使用SQL Server 2012的DTS向导(Import and Export Data/导入导出数据)时,会出现如下问题: 当来源数据直接使用表的时候,没有任何问题 但如果来源数据是查询时,就 ...
- HBase学习笔记——配置及Shell操作
1.HBase的配置 还是以前配置的集群,见:http://www.cnblogs.com/DarrenChan/p/6493373.html 我们约定:weekend03和weekend04放HMa ...
- 简单解决Ubuntu修改locale的问题
本文针对的问题是“Ubuntu 安装中文语言包”“Ubuntu Server中文问题”,“Ubuntu更改语言环境”,“Ubuntu locale的设定”,“cannot change local ...
- 请用正则表达式匹配出QQ号(假设QQ号码为5—10位);
请用正则表达式匹配出QQ号(假设QQ号码为5—10位): 解答: ^ \d{5,10}$