基本思路

用户提交表单后,验证开始。页面中会有多个域要求验证,如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. ES6 Class语法学习

    前言 大多数面向对象的编程语言都支持类和类继承的特性,而JS却不支持这些特性,只能通过其他方法定义并关联多个相似的对象,这种状态一直延续到了ES5.由于类似的库层出不穷,最终还是在ECMAScript ...

  2. Spring IOC容器对bean的生命周期进行管理的过程

    1.通过构造器或者工厂方法创建bean的实例 2.为bean的属性设置值和对其他bean的引用 3.将bean的实例传递给bean的后置处理器BeanPostProcessor的postProcess ...

  3. [物理学与PDEs]第5章第6节 弹性静力学方程组的定解问题

    5. 6 弹性静力学方程组的定解问题 5. 6. 1 线性弹性静力学方程组 1.  线性弹性静力学方程组 $$\bee\label{5_6_1_le} -\sum_{j,k,l}a_{ijkl}\cf ...

  4. spring cloud(学习笔记)高可用注册中心(Eureka)的实现(一)

    最近在学习的时候,发现微服务架构中,假如只有一个注册中心,那这个注册中心挂了可怎么办,这样的系统,既不安全,稳定性也不好,网上和书上找了一会,发现这个spring cloud早就想到了,并帮我们解决了 ...

  5. 版本控制工具 - TortoiseSVN

    版本控制工具 - TortoiseSVN 使用SVN需要安装三个软件,Visual SVN Server是用于存储项目仓库的中央服务器,Tortoise SVN是管理版本控制的软件,Visual SV ...

  6. 【转载】MySQL5.7 添加用户、删除用户与授权

    mysql -uroot -proot MySQL5.7 mysql.user表没有password字段改 authentication_string: 一. 创建用户: 命令:CREATE USER ...

  7. pm2,部署nodejs,使用方法及自己使用后总结的经验

    pm2是一个带有负载均衡功能的应用进程管理器,可以用它来管理你的node进程,并查看node进程的状态,当然也支持性能监控,进程守护等功能.他会确定重启开机之后,能够保证程序也能运行起来.目前还没有操 ...

  8. 原生javascript实现阻止浏览器默认行为与阻止事件冒泡

    不同的浏览器之间存在兼容问题,在IE与标准浏览器之间存在很大的差异,所以在实现阻止浏览器默认行为和阻止事件冒泡就要考虑要它们之间的不同 /** * 取消冒泡 * @param {事件} e */ fu ...

  9. js中循环对比(for循环,foreach,for in,for of ,map)

    对空位的处理 for循环(不会忽略空位,标记undefined) var arr =[1,2,undefined,3,null,,7] for (let i=0;i<arr.length;i++ ...

  10. docker 进阶

    docker 常用命令: docker  pull hub.c.163.com/library/mysql:latest  #这是从网址下载下来mysql镜像 docker run  -d -p 88 ...