基本思路

用户提交表单后,验证开始。页面中会有多个域要求验证,如text input,files, checkbox。同时,根据验证字段的不同,验证方式会有很多种,例如对邮箱、IP地址、电话的验证标准就各不相同。那么就要设计不同的验证标准,并且在将所有待验证域验证完毕后,返回验证是否成功的结果。这就是基本的实现了。

我们还可以将验证机制做得更细致、更友好些。第一点,并不是所有域名都是必须输入,也会有一些空着也无妨的域。那就可以对不同域做出区分。第二点,用户输入出错和空着没填,我们也可以区分开来,并且在前端动态地提示用户。第三点,对于每个用户输入域,我们都是获取用户输入,并拿自己定义的标准比对,这个过程其实是可以复用的,那是不是可以写一个基类将这些过程抽象并封装,让每个域去继承这一基本流程呢?

文件结构

两个启动文件,对应的分别的是基本表单验证实现和完整的验证实现。

HTML文件

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Form验证</title>
<style>
.inputs_1{margin-left:36px;}
.inputs_2{margin-left:50px;}
.inputs_3{margin-left:18px;}
</style>
</head>
<body>
<form action="/index" method="post" enctype="multipart/form-data">
IP地址<input type="text" name="ip" class="inputs_1">
<span style="color:red;">
{{ display_error_info(error_message_dict, 'ip') }}
</span><br>
<p>
<input type="checkbox" name="game" value="1">马里奥
<input type="checkbox" name="game" value="2">塞尔达
<input type="checkbox" name="game" value="3">星之卡比
</p>
<span style="color:red;">
{{ display_error_info(error_message_dict, 'game') }}
</span><br>
<input type="file" name="files"/>
<input type="file" name="files"/>
<input type="submit" value="提交">
<span style="color:red;">
{{ display_error_info(error_message_dict, 'files') }}
</span><br>
</form> </body>
</html>

验证的基本实现

import tornado.ioloop
import tornado.web class MainForm(object):
# MainForm类的字段就是要匹配的输入域,值是匹配模式
# 其中对checkbox和files两个域,暂时简单地用判断列表有无元素进行检测
def __init__(self):
# 匹配IP地址这里折腾了很久,一致尝试使用命名分组,却一直无法成功,
# 不懂怎么回事,不想再看正则这一部分了,先放一放
# 注意尖角号和美元符的作用:匹配字符串开头和结尾的位置
# match从头匹配,没有则None,search则是匹配到
self.ip = "^(25[0-5]|2[0-4][0-9]|[0-1]?[0-9]?[0-9])(\.(25[0-5]|2[0-4][0-9]|[0-1]?[0-9]?[0-9])){3}$"
self.email = "^\w+@\w+\.\w+"
self.phone = "1[3|7|5|8]\d{8}"
self.game = []
self.files = [] def check_valid(self, handler):
import re
# 获取了对象的所有字段,形式是一个字典,键值分别是字段和字段的值
form_dict = self.__dict__
flag = True
# 用户输入的值也储存在一个字典中
user_dict = {}
# 这里我们迭代form_dict的所有元素
for key, pattern in form_dict.items():
if key == 'game':
user_value = handler.get_arguments(key)
is_valid = False if not user_value else True
elif key == 'files':
user_value = handler.request.files.get(key)
is_valid = False if not user_value else True
else:
user_value = handler.get_argument(key)
is_valid = re.match(pattern, user_value)
if not is_valid:
flag = False
user_dict[key] = user_value
return flag, user_dict class IndexHandler(tornado.web.RequestHandler):
def get(self):
self.render('index.html') def post(self):
# 用户提交数据后,会生成一个MainForm()对象
_formVali = MainForm()
flag, user_inputs = _formVali.check_valid(self)
print(flag, user_inputs) settings = {
"template_path": "views", # 配置html文件路径
"static_path": "statics", # 配置静态文件路径
} # 路由映射
application = tornado.web.Application([
(r"/index", IndexHandler),
], **settings) # 启动
if __name__ == "__main__":
application.listen(8001)
tornado.ioloop.IOLoop.instance().start()

类封装后的验证实现

import tornado.ioloop
import tornado.web
import re
import myuimethod class IPField:
REGULAR = "^(25[0-5]|2[0-4][0-9]|[0-1]?[0-9]?[0-9])(\.(25[0-5]|2[0-4][0-9]|[0-1]?[0-9]?[0-9])){3}$" def __init__(self, error_dict=None, required=True):
# 封装自定义错误信息,格式为错误类型-错误信息
self.error_dict = {}
if error_dict:
self.error_dict.update(error_dict)
self.required = required
# 用于返回给check_valid函数,让其判断输入是否全部合法
self.is_valid = False
# 封装了用户输入的值
self.value = None
# 封装了具体的错误信息
self.error = None def validate(self, name, user_value):
# 传入参数:域名、用户输入值
# 是否要求必须输入
if not self.required:
self.is_valid = True
self.value = user_value
else:
# 输入是否为空
if not user_value.strip():
# 是否自定义了域不可为空的错误信息
if self.error_dict.get("required", None):
self.error = self.error_dict['required']
else:
self.error = "%s is required." % name
else:
match_obj = re.match(IPField.REGULAR, user_value)
# 是否匹配成功
if match_obj:
self.is_valid = True
self.value = match_obj.group()
else:
# 是否定义了非法输入的错误信息
if self.error_dict.get('valid', None):
self.error = self.error_dict['valid']
else:
self.error = "%s is invalid." % name class CheckboxField:
def __init__(self, error_dict=None, required=True):
self.error_dict = {}
if error_dict:
self.error_dict.update(error_dict)
self.required = required
self.is_valid = False
self.value = None
self.error = None def validate(self, name, user_value):
"""
:param name: 域名 game
:param user_value: 用户勾选的内容 形如[1,2,3]
:return:
"""
if not self.required:
self.is_valid = True
self.value = user_value
else:
if not user_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 = user_value class FileField:
REGULAR = r'(\w+.jpg)|(\w+.jpeg)|(\w+.gif)|(\*+.png)' def __init__(self, error_dict=None, required=True):
self.name = None
self.error = None
# 封装了符合规范的文件名
self.value = []
# 上传文件一项是否符合规范,默认为True,验证中一旦有不合法的地方就将其改为False
self.is_valid = True
self.required = required
# 存储最终成功上传的文件路径
self.success_file_list = []
# 将错误信息封装在字典中
self.error_dict = {}
# 如果自定义了错误信息,则更新默认字典
if error_dict:
self.error_dict.update(error_dict) def validate(self, name, file_name_list):
self.name = name
# 根据文件上传是否必须,区分为两大场景
if not self.required:
self.is_valid = True
# 所有合法的文件列表,文件可能有1个没有上传,也有可能文件后缀或大小不符合要求
self.success_file_list = file_name_list
else:
# 要求上传文件却没有上传
if not file_name_list:
self.is_valid = False
if self.error_dict.get('required', None):
self.error = self.error_dict['required']
else:
self.error = 'Files not selected and uploaded.'
else:
for file_name in file_name_list:
# 文件是否符合规范
if not re.match(FileField.REGULAR, file_name):
self.is_valid = False
if self.error_dict.get('error', None):
self.error = self.error_dict['error']
else:
self.error = '%s is invalid' % file_name
else:
self.value.append(file_name) def save(self, files_obj, path=''):
import os
for file_obj in files_obj:
file_name = file_obj['filename']
full_file_name = os.path.join(path, file_name)
print(full_file_name)
# 文件名不为空你且文件名在合法文件列表中
if file_name and file_name in self.value:
self.success_file_list.append(full_file_name)
with open(full_file_name, 'wb') as f:
f.write(file_obj['body']) class BaseForm:
def check_valid(self, handler):
flag = True
error_message_dict = {}
success_dict = {}
# Form类继承自BaseForm类,self.__dict__内封装了派生类的所有字段
# key是字段名,regOBj则是对应的正则对象
for key, regObj in self.__dict__.items():
# key: 输入域
if type(regObj) == CheckboxField:
user_value = handler.get_arguments(key)
elif type(regObj) == FileField:
# form表单内有文件上传时,一定要将enctype属性设置为multipart/form-data,否则服务端收不到文件数据
# files_obj是一个列表,元素是字典,有键filename和body,封装了文件名和文件内容
files_obj = handler.request.files.get(key)
user_value = []
# 如果没有上传任何文件,files_obj将是NoneType无法迭代,迭代前需判断
if files_obj:
for file in files_obj:
user_value.append(file['filename'])
else:
user_value = handler.get_argument(key)
# 将验证过程放入对应域的正则对象中
# 这样可以将不同的验证规则封装到不同的类中
regObj.validate(key, user_value)
# 验证信息封装在regObj中
if regObj.is_valid:
success_dict[key] = regObj.value
regObj.save(files_obj)
else:
flag = False
error_message_dict[key] = regObj.error
return flag, success_dict, error_message_dict class IndexForm(BaseForm):
def __init__(self):
self.ip = IPField(required=True)
self.game = CheckboxField(required=True)
self.files = FileField(required=True) class IndexHandler(tornado.web.RequestHandler):
def get(self):
self.render('index.html', error_message_dict={}) def post(self):
_formVali = IndexForm()
flag, success_dict, error_message_dict = _formVali.check_valid(self)
if flag:
print('success', success_dict)
else:
print('error', error_message_dict)
self.render('index.html', error_message_dict=error_message_dict) settings = {
"template_path": "views", # 配置html文件路径
"static_path": "statics", # 配置静态文件路径
"ui_methods": myuimethod # 配置模板方法文件
} # 路由映射
application = tornado.web.Application([
(r"/index", IndexHandler),
], **settings) # 启动
if __name__ == "__main__":
application.listen(8001)
tornado.ioloop.IOLoop.instance().start()
def display_error_info(self, error_dict, key):
if error_dict.get(key):
return error_dict[key]
else:
return ''

myuimethod

Tornado-Form表单验证的更多相关文章

  1. 抽屉之Tornado实战(7)--form表单验证

    在这里,我们把form表单验证的代码进行工具化了,以后稍微修改一下参数就可以拿来用了 先贴上代码 forms.py from backend.form import fields class Base ...

  2. python26:自定义form表单验证

    一.自定义Form的原理 1.1 各种form表单验证比较 只有python提供了form表单验证,其他的都没有提供.django提供的功能还不够强大.最强大的是微软的ASP.NET!我们可以自己写一 ...

  3. Form表单验证组件

    Tyrion是一个基于Python实现的支持多个WEB框架的Form表单验证组件,其完美的支持Tornado.Django.Flask.Bottle Web框架.Tyrion主要有两大重要动能: 表单 ...

  4. form表单验证-Javascript

    Form表单验证: js基础考试内容,form表单验证,正则表达式,blur事件,自动获取数组,以及css布局样式,动态清除等.完整代码如下: <!DOCTYPE html PUBLIC &qu ...

  5. django之form表单验证

    django中的Form一般有两种功能: 输入html 验证用户输入 #!/usr/bin/env python # -*- coding:utf- -*- import re from django ...

  6. python_way day19 HTML-day5 (form表单验证,CSRF,cookie,session,缓存)

    python-way day19 1. dJango的form表单验证 2.CSRF 跨站请求伪造 3.cookie,session 4.缓存 一,django表单验证功能 1.django验证基础: ...

  7. form表单验证2

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  8. Day19 Django之Form表单验证、CSRF、Cookie、Session和Model操作

    一.Form表单验证 用于做用户提交数据的验证1.自定义规则 a.自定义规则(类,字段名==html中的name值)b.数据提交-规则进行匹配代码如下: """day19 ...

  9. [php基础]PHP Form表单验证:PHP form validator使用说明

    在PHP网站开发建设中,用户注册.留言是必不可少的功能,用户提交的信息数据都是通过Form表单提交,为了保证数据的完整性.安全性,PHP Form表单验证是过滤数据的首要环节,PHP对表单提交数据的验 ...

  10. django form表单验证

    一. django form表单验证引入 有时时候我们需要使用get,post,put等方式在前台HTML页面提交一些数据到后台处理例 ; <!DOCTYPE html> <html ...

随机推荐

  1. 金融量化分析【day112】:股票数据分析Tushare1

    目录 1.使用tushare包获取某股票的历史行情数据 2.输出该股票所有收盘比开盘上涨3%以上的日期 3.输出该股票所有开盘比前日收盘跌幅超过2%的日期 4.假如我从2010年1月1日开始,每月第一 ...

  2. Typora使用说明(记录总结)

    目录 区域元素 YAML FONT Matters 菜单 段落 标题 引注 序列 可选序列 代码块 数学块 表格 脚注 水平线 特征元素 链接 超链接 内链接 相关链 URLs 图片 斜体 加粗 删除 ...

  3. python的os.system函数的应用

    os的system原理 system函数可以将字符串转化成命令在服务器上运行:其原理是每一条system函数执行时,其会创建一个子进程在系统上执行命令行,子进程的执行结果无法影响主进程 上述原理会导致 ...

  4. mac下go环境搭建开发web工程

    1,golang下载: http://www.golangtc.com/download https://golang.org/ https://beego.me/docs/intro/ 2,安装go

  5. 查看和设置MySQL数据库字符集(转)

    查看和设置MySQL数据库字符集作者:scorpio 2008-01-21 10:05:17 标签: 杂谈 Liunx下修改MySQL字符集:1.查找MySQL的cnf文件的位置find / -ina ...

  6. JS中some(),every(),forEach(),map(),filter()区别

    JS在1.6中为Array新增了几个方法map(),filter(),some(),every(),forEach(),也就是一共有这么多方法了. 刚开始接触这些倒也记得不是很清楚,在此纪录一下以加深 ...

  7. 网络学习day01_计算机网络与分层思想

    2018.9.1 网络学习day01_计算机网络与分层思想 网络安全 计算机网络 分层思想    LAN与WAN   LAN(Local Area Network)--局域网   局域网(Local ...

  8. java获取当前运行的方法名称

    // 这种方式获取的话,数组的第一个元素是当前运行方法的名称,第二个元素是调用当前方法的方法名称 StackTraceElement[] stackTrace = new Exception().ge ...

  9. JVM--01

    ---恢复内容开始--- jdk  jre  jvm 的关系 java7的结构图 java8 jvm内存溢出 jdk /bin 目录下的jconsole java发展历史 oak:用在嵌入式设备上 相 ...

  10. MS SQL Server NULL处理

    -- 首先在用户表中插入数据如下 TRUNCATE TABLE UserInfo ; INSERT INTO userinfo(UserName,UserLogin,UserPassword,User ...