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

在这里,我们把form表单验证的代码进行工具化了,以后稍微修改一下参数就可以拿来用了

  先贴上代码

forms.py

from backend.form import fields

class BaseForm:

    def __init__(self):
self._value_dict = {}
self._error_dict = {}
self._valid_status = True def valid(self, handler): for field_name, field_obj in self.__dict__.items():
if field_name.startswith('_'):
continue if type(field_obj) == fields.CheckBoxField:
post_value = handler.get_arguments(field_name, None)
elif type(field_obj) == fields.FileField:
post_value = []
file_list = handler.request.files.get(field_name, [])
for file_item in file_list:
post_value.append(file_item['filename'])
else:
post_value = handler.get_argument(field_name, None) field_obj.match(field_name, post_value)
if field_obj.is_valid:
self._value_dict[field_name] = field_obj.value
else:
self._error_dict[field_name] = field_obj.error
self._valid_status = False
return self._valid_status

fields.py

import re
import os class Field: def __init__(self): self.is_valid = False
self.name = None
self.value = None
self.error = None def match(self, name, value):
self.name = name if not self.required:
self.is_valid = True
self.value = value
else:
if not value:
if self.custom_error_dict.get('required', None):
self.error = self.custom_error_dict['required']
else:
self.error = "%s is required" % name
else:
ret = re.match(self.REGULAR, value)
if ret:
self.is_valid = True
self.value = value
else:
if self.custom_error_dict.get('valid', None):
self.error = self.custom_error_dict['valid']
else:
self.error = "%s is invalid" % name class StringField(Field): REGULAR = "^.*$" def __init__(self, custom_error_dict=None, required=True): self.custom_error_dict = {} # {'required': 'IP不能为空', 'valid': 'IP格式错误'}
if custom_error_dict:
self.custom_error_dict.update(custom_error_dict) self.required = required super(StringField, self).__init__() class IPField(Field): 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, custom_error_dict=None, required=True): self.custom_error_dict = {} # {'required': 'IP不能为空', 'valid': 'IP格式错误'}
if custom_error_dict:
self.custom_error_dict.update(custom_error_dict) self.required = required
super(IPField, self).__init__() class EmailField(Field): REGULAR = "^\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$" def __init__(self, custom_error_dict=None, required=True): self.custom_error_dict = {} # {'required': 'IP不能为空', 'valid': 'IP格式错误'}
if custom_error_dict:
self.custom_error_dict.update(custom_error_dict) self.required = required
super(EmailField, self).__init__() class IntegerField(Field): REGULAR = "^\d+$" def __init__(self, custom_error_dict=None, required=True): self.custom_error_dict = {} # {'required': 'IP不能为空', 'valid': 'IP格式错误'}
if custom_error_dict:
self.custom_error_dict.update(custom_error_dict) self.required = required
super(IntegerField, self).__init__() class CheckBoxField(Field): REGULAR = "^\d+$" def __init__(self, custom_error_dict=None, required=True): self.custom_error_dict = {} # {'required': 'IP不能为空', 'valid': 'IP格式错误'}
if custom_error_dict:
self.custom_error_dict.update(custom_error_dict) self.required = required
super(CheckBoxField, self).__init__() def match(self, name, value):
self.name = name if not self.required:
self.is_valid = True
self.value = value
else:
if not value:
if self.custom_error_dict.get('required', None):
self.error = self.custom_error_dict['required']
else:
self.error = "%s is required" % name
else:
if isinstance(name, list):
self.is_valid = True
self.value = value
else:
if self.custom_error_dict.get('valid', None):
self.error = self.custom_error_dict['valid']
else:
self.error = "%s is invalid" % name class FileField(Field): REGULAR = "^(\w+\.pdf)|(\w+\.mp3)|(\w+\.py)$" def __init__(self, custom_error_dict=None, required=True): self.custom_error_dict = {} # {'required': 'IP不能为空', 'valid': 'IP格式错误'}
if custom_error_dict:
self.custom_error_dict.update(custom_error_dict) self.required = required super(FileField, self).__init__() def match(self, name, file_name_list):
flag = True
self.name = name if not self.required:
self.is_valid = True
self.value = file_name_list
else:
if not file_name_list:
if self.custom_error_dict.get('required', None):
self.error = self.custom_error_dict['required']
else:
self.error = "%s is required" % name
flag = False
else:
for file_name in file_name_list:
if not file_name or not file_name.strip():
if self.custom_error_dict.get('required', None):
self.error = self.custom_error_dict['required']
else:
self.error = "%s is required" % name
flag = False
break
else:
ret = re.match(self.REGULAR, file_name)
if not ret:
if self.custom_error_dict.get('valid', None):
self.error = self.custom_error_dict['valid']
else:
self.error = "%s is invalid" % name
flag = False
break self.is_valid = flag def save(self, request, upload_to=""): file_metas = request.files[self.name]
for meta in file_metas:
file_name = meta['filename']
file_path_name = os.path.join(upload_to, file_name)
with open(file_path_name, 'wb') as up:
up.write(meta['body']) upload_file_path_list = map(lambda path: os.path.join(upload_to, path), self.value)
self.value = list(upload_file_path_list)

在form.py这个文件,做了一件什么事呢?代码就定义了父类,主要是判断要验证内容的类型,然后取值,然后又调用了在fields.py里类的match方法,最后把验证后结果信息返回(vaild方法)。

  而在fields.py文件里,主要是对为空检测,合法性检测,并把检测结果返回给form.py的vaild方法里(match方法)

首先

  • form组件只做为空检测,合法性检测,并没做超时检测,内部可获取验证状态_valid_status--True/False,错误信息_error_dict,验证通过时的用户数据_value_dict

  • 验证类型:字符串,IP,邮箱,数字,复选框,文件

再者,怎么用?

  • 分析你的应用场景,需要对哪几个类型进行验证,定义一个类,把需要的验证类型写入到构造方法里,记得继承一下BaseForm类,并且继承一下父类的构造方法

  • 在构造方法里,实例Field对象时,可以传入自定制错误类型信息custom_error_dict,required=False可为空设置

    from backend.form.forms import BaseForm
    from backend.form.fields import StringField
    from backend.form.fields import IntegerField
    from backend.form.fields import EmailField class SendMsgForm(BaseForm): def __init__(self):
    self.email = EmailField(custom_error_dict={'required': '注册邮箱不能为空.', 'valid': '注册邮箱格式错误.'}) super(SendMsgForm, self).__init__() class RegisterForm(BaseForm): def __init__(self):
    self.username = StringField()
    self.email = EmailField()
    self.password = StringField()
    self.email_code = StringField() super(RegisterForm, self).__init__() class LoginForm(BaseForm): def __init__(self):
    self.user = StringField()
    self.pwd = StringField()
    self.code = StringField() super(LoginForm, self).__init__()

    最后

    • 在post方法里,调用一下form对象的vaild方法(把handler对象,也就是self传入),接下来只要根据form对象里检测完后的信息进行相应的操作

import io
import datetime
import json
from backend.utils import check_code
from backend.core.request_handler import BaseRequestHandler
from forms import account
from backend.utils.response import BaseResponse
from backend import commons
from models import chouti_orm as ORM
from sqlalchemy import and_, or_ class CheckCodeHandler(BaseRequestHandler):
def get(self, *args, **kwargs):
stream = io.BytesIO()
img, code = check_code.create_validate_code()
img.save(stream, "png")
self.session["CheckCode"] = code
self.write(stream.getvalue()) class LoginHandler(BaseRequestHandler):
def post(self, *args, **kwargs):
#对象里有self.status=False,self.data=None,self.summary=None,self.message={}
rep = BaseResponse()
form = account.LoginForm()
if form.valid(self):
if form._value_dict['code'].lower() != self.session["CheckCode"].lower():
rep.message = {'code': '验证码错误'}
self.write(json.dumps(rep.__dict__))
return
conn = ORM.session()
obj = conn.query(ORM.UserInfo).filter(
or_(
and_(ORM.UserInfo.email == form._value_dict['user'],
ORM.UserInfo.password == form._value_dict['pwd']),
and_(ORM.UserInfo.username == form._value_dict['user'],
ORM.UserInfo.password == form._value_dict['pwd'])
)).first()
if not obj:
rep.message = {'user': '用户名邮箱或密码错误'}
self.write(json.dumps(rep.__dict__))
return self.session['is_login'] = True
self.session['user_info'] = obj.__dict__
rep.status = True
else:
rep.message = form._error_dict
self.write(json.dumps(rep.__dict__)) class RegisterHandler(BaseRequestHandler):
def post(self, *args, **kwargs):
rep = BaseResponse()
form = account.RegisterForm()
if form.valid(self):
current_date = datetime.datetime.now()
limit_day = current_date - datetime.timedelta(minutes=1)
conn = ORM.session()
is_valid_code = conn.query(ORM.SendMsg).filter(ORM.SendMsg.email == form._value_dict['email'],
ORM.SendMsg.code == form._value_dict['email_code'],
ORM.SendMsg.ctime > limit_day).count()
if not is_valid_code:
rep.message['email_code'] = '邮箱验证码不正确或过期'
self.write(json.dumps(rep.__dict__))
return
has_exists_email = conn.query(ORM.UserInfo).filter(ORM.UserInfo.email == form._value_dict['email']).count()
if has_exists_email:
rep.message['email'] = '邮箱已经存在'
self.write(json.dumps(rep.__dict__))
return
has_exists_username = conn.query(ORM.UserInfo).filter(
ORM.UserInfo.username == form._value_dict['username']).count()
if has_exists_username:
rep.message['email'] = '用户名已经存在'
self.write(json.dumps(rep.__dict__))
return
form._value_dict['ctime'] = current_date
form._value_dict.pop('email_code')
obj = ORM.UserInfo(**form._value_dict)
conn.add(obj)
conn.query(ORM.SendMsg).filter_by(email=form._value_dict['email']).delete()
conn.commit()
self.session['is_login'] = True
self.session['user_info'] = obj.__dict__
rep.status = True else:
rep.message = form._error_dict self.write(json.dumps(rep.__dict__)) class SendMsgHandler(BaseRequestHandler):
def post(self, *args, **kwargs):
rep = BaseResponse()
form = account.SendMsgForm()
if form.valid(self):
email = form._value_dict['email']
conn = ORM.session() has_exists_email = conn.query(ORM.UserInfo).filter(ORM.UserInfo.email == form._value_dict['email']).count()
if has_exists_email:
rep.summary = "此邮箱已经被注册"
self.write(json.dumps(rep.__dict__))
return
current_date = datetime.datetime.now()
code = commons.random_code() count = conn.query(ORM.SendMsg).filter_by(**form._value_dict).count()
if not count:
insert = ORM.SendMsg(code=code,
email=email,
ctime=current_date)
conn.add(insert)
conn.commit()
rep.status = True
else:
limit_day = current_date - datetime.timedelta(hours=1)
times = conn.query(ORM.SendMsg).filter(ORM.SendMsg.email == email,
ORM.SendMsg.ctime > limit_day,
ORM.SendMsg.times >= 10,
).count()
if times:
rep.summary = "'已经超过今日最大次数(1小时后重试)'"
else:
unfreeze = conn.query(ORM.SendMsg).filter(ORM.SendMsg.email == email,
ORM.SendMsg.ctime < limit_day).count()
if unfreeze:
conn.query(ORM.SendMsg).filter_by(email=email).update({"times": 0}) conn.query(ORM.SendMsg).filter_by(email=email).update({"times": ORM.SendMsg.times + 1,
"code": code,
"ctime": current_date},
synchronize_session="evaluate")
conn.commit()
rep.status = True
else:
rep.summary = form._error_dict['email']
self.write(json.dumps(rep.__dict__))
上一篇:2018年冬季寒假作业4--PTA 打印沙漏


下一篇:JS通用表单验证函数,基于javascript正则表达式