web.py開發web 第八章 Formalchemy 服務端驗證

    上一章講了如何使用formalchemy+jinja2建立表單,這一章將要講formalchemy在服務器端怎麼對錶單數據驗證。咱們用前面的User表單來進行舉例,User中有幾個地方須要驗證,下面一一列出來: html

  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用於存放自定義的驗證方法。 python

customValidators.py web

#-*- 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 sql

#-*- 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/,用各類不規則的數據提交吧,看看驗證是否都有做用:)
相關文章
相關標籤/搜索