当前位置: 首页 > news >正文

web.py开发web 第八章 Formalchemy 服务端验证

2019独角兽企业重金招聘Python工程师标准>>> hot3.png

    上一章讲了如何使用formalchemy+jinja2创建表单,这一章将要讲formalchemy在服务器端怎么对表单数据验证。我们用前面的User表单来进行举例,User中有几个地方需要验证,下面一一列出来:

  1. name字段必填且数据库内唯一,长度不小于6,不大于20。
  2. email字段必填且数据库内唯一,且为email格式,长度不大于32。
  3. password必填,长度不小于6,不大于32。
  4. confirm password必填且必须与password相等,长度不小于6,不大于32。

    以上为针对User表单需要验证的内容,验证需求中的必填/长度限制在formalchemy的validator中已经内建,那么验证唯一和验证两个password是否相等还需要我们自定义下验证方法,这里是formalchemy关于自定义验证方法的文档,下面上这两个自定义方法的代码,先在app根目录下创建一个customValidators.py用于存放自定义的验证方法。

customValidators.py

#-*- coding: utf-8 -*-
from formalchemy import ValidationError

#检验两个字段的值是否相等
def customEqual(equal_field, message):
    def check(value, field):
        if field.is_required() or (not field.is_required() and value):
            if getattr(field.parent, equal_field).value != value:
                raise ValidationError(message)
    return check

#检验字段值在数据库中是否唯一,并可设置是否忽略自身值,这在编辑已有信息的时候验证唯一非常有用
def customUnique(session, message="此数据已存在", checkSelf=False):
    def check(value, field):
        model = field.model.__class__
        if checkSelf:
            query = session.query(model).filter(
                (getattr(model, field.name)==value) &
                (model.id!=field.model.id)
            ).first()
        else:
            query = session.query(model).filter(getattr(model, field.name)==value).first()
        if query:
            raise ValidationError(message)
    return check
     接下来让我们修改上一章的forms.py,把验证信息加入进去。
forms.py
#-*- coding:utf-8 -*-
from formalchemy import config, validators, Field, FieldSet
from customEngine import Jinja2Engine
from models import *
from customValidators import *

class UserForm:
    def __init__(self):
        #这里的directories是指表单模板存放的地方,我们在第二章提到的templates下创建一个文件夹,命名为form
        config.engine = Jinja2Engine(directories=["templates/form"])

    #为表单设置label
    def setLabel(self):
        self.name = self.fs.name.label("User Name")
        self.email = self.fs.email.label("Email Address")
        self.password = self.fs.password.label("Password")
        self.superuser = self.fs.superuser.label("Admin?")

    #定义编辑模式下通用的设置,编辑模式包括:新增,修改
    def wmode(self, password=None):
        self.setLabel()

        #因为新增和修改中都需要用户重新确认密码,所以要为表单加入Confirm Password
        #如果有指定password的值,说明用户是在修改记录,那么Confirm Password也必须有值
        if not password:
            self.fs.insert_after(self.fs.password, Field("confirm_password"))
        else:
            self.fs.insert_after(self.fs.password, Field("confirm_password", value=password))
        self.confirm_password = self.fs.confirm_password.label("Re-enter Password")

        self.name = self.name.required().validate(
            validators.length(min=6, max=20)
        )
        self.email = self.email.required().email().validate(
            validators.email
        ).validate(
            validators.maxlength(32)
        )
        self.password = self.password.required().password().validate(
            validators.length(min=6, max=32)
        )
        self.confirm_password = self.confirm_password.required().password().validate(
            validators.length(min=6, max=32)
        ).validate(
            customEqual("password", "密码前后不一致")
        )

    #定义新增用户时调用的方法
    def write_render(self, cls):
        #设置Fieldset对象,指定要绑定的sqlalchemy中的表类,并赋予sqlalchemy的session
        self.fs = FieldSet(User, session=cls.db)
        self.wmode()

        #配置表单信息
        self.fs.configure(
            #表单包含的字段
            include=[
                self.name.validate(customUnique(cls.db)),
                self.email.validate(customUnique(cls.db)),
                self.password,
                self.confirm_password
            ]
        )
        return self.fs
     为了触发验证,需要提交表单,我们为main.py的showform类添加POST方法,main.py整体修改如下。

main.py

#-*- coding:utf-8 -*-
import web, middleware
from web.contrib.template import render_jinja
from models import *
from forms import *
import sys
reload(sys)
sys.setdefaultencoding("utf-8")

urls = (
    "/", "index",
    "/form/", "showform",
)
app = web.application(urls, globals())
app.add_processor(middleware.set_orm)

render = render_jinja(
    'templates',
    encoding = 'utf-8',
)

class BaseView(object):
    def __init__(self):
        #从web.ctx.orm获取session放入基类的db中
        self.db = web.ctx.orm

class index(BaseView):
    def GET(self):
        return render.index()

class showform(BaseView):
    def __init__(self):
        super(showform, self).__init__()
        form = UserForm()
        self.fs = form.write_render(self)

    def GET(self):
        return render.form(form=self.fs)

    def POST(self):
        data = web.input()
        self.fs.rebind(data=data)
        if self.fs.validate():
            self.fs.sync()
            return "success"
        return render.form(form=self.fs)

if __name__ == "__main__":
    app.run()
     下面运行main.py,访问/form/,用各种不规则的数据提交吧,看看验证是否都有作用:)

转载于:https://my.oschina.net/zhengnazhi/blog/122391

相关文章:

  • 邮件服务器postfix+dovecot+mysql
  • 基于 J2EE 网银系统的安全系统解决方案概述
  • 第十六天 switch case break
  • 程序员算法练习二
  • Cocos2d-x Eclipse下程序运行产生错误Effect initCheck() returned -1
  • 作业调度与管理
  • 以太坊又一次大拥堵何去何从?深度对话美图以太坊DPoS算法实现团队
  • linux git命令参数及用法详解--版本控制工具
  • express 遇到问题 - Error: Can't set headers after they are sent
  • 图文介绍openLDAP在windows上的安装配置
  • 新模板电子版发布
  • Tomcat绑定具体IP
  • Heritrix 3.1.0 源码解析(十二)
  • oracle alert 日志位置
  • 转:字符编码笔记:SCII,Unicode和UTF-8
  • #Java异常处理
  • 3.7、@ResponseBody 和 @RestController
  • Git 使用集
  • iBatis和MyBatis在使用ResultMap对应关系时的区别
  • JavaScript 基础知识 - 入门篇(一)
  • Java-详解HashMap
  • js递归,无限分级树形折叠菜单
  • JS函数式编程 数组部分风格 ES6版
  • leetcode讲解--894. All Possible Full Binary Trees
  • Redis 中的布隆过滤器
  • spring cloud gateway 源码解析(4)跨域问题处理
  • Webpack 4 学习01(基础配置)
  • 安卓应用性能调试和优化经验分享
  • 初识 beanstalkd
  • 爬虫进阶 -- 神级程序员:让你的爬虫就像人类的用户行为!
  • 七牛云假注销小指南
  • 前端每日实战:61# 视频演示如何用纯 CSS 创作一只咖啡壶
  • 区块链共识机制优缺点对比都是什么
  • 如何利用MongoDB打造TOP榜小程序
  • 探索 JS 中的模块化
  • 微信支付JSAPI,实测!终极方案
  • 远离DoS攻击 Windows Server 2016发布DNS政策
  • Play Store发现SimBad恶意软件,1.5亿Android用户成受害者 ...
  • ​软考-高级-系统架构设计师教程(清华第2版)【第9章 软件可靠性基础知识(P320~344)-思维导图】​
  • # C++之functional库用法整理
  • #考研#计算机文化知识1(局域网及网络互联)
  • #我与Java虚拟机的故事#连载15:完整阅读的第一本技术书籍
  • (pt可视化)利用torch的make_grid进行张量可视化
  • (附源码)spring boot公选课在线选课系统 毕业设计 142011
  • (简单有案例)前端实现主题切换、动态换肤的两种简单方式
  • (十一)JAVA springboot ssm b2b2c多用户商城系统源码:服务网关Zuul高级篇
  • (实战)静默dbca安装创建数据库 --参数说明+举例
  • (转)Linux下编译安装log4cxx
  • (转)Mysql的优化设置
  • (转)大道至简,职场上做人做事做管理
  • (转)母版页和相对路径
  • (转载)虚幻引擎3--【UnrealScript教程】章节一:20.location和rotation
  • ******之网络***——物理***
  • *Django中的Ajax 纯js的书写样式1
  • .\OBJ\test1.axf: Error: L6230W: Ignoring --entry command. Cannot find argumen 'Reset_Handler'