安装deform
pip install pyramid_deform
pip install js.deform
deform表单库介绍
与pyramid同属Pylons Project表单库
Colander:定义表单结构
Peppercom:序列化和反序列化
Chameleon:模板引擎
development.ini里导入pyramid_deform
[app:main] use = egg:MyShop pyramid.reload_templates = true pyramid.debug_authorization = true pyramid.debug_notfound = false pyramid.debug_routematch = false pyramid.default_locale_name = en pyramid.includes = pyramid_debugtoolbar pyramid_tm pyramid_layout pyramid_deform
创建lib/deforms.py文件
# -*- coding:UTF-8 -*- import colander import deform from js.deform import deform as deform_static class LoginFormSchema(colander.MappingSchema): # 定义一个LoginFormSchema表单结构 MappingSchema表示一个映射类型 username = colander.SchemaNode(colander.Str()) # colander.SchemaNode相当于定义的Column password = colander.SchemaNode(colander.Str(), widget=deform.widget.PasswordWidget() # 使密码密文显示 ) email = colander.SchemaNode(colander.Str(), validator=colander.Email() # 验证器 验证邮箱是否合法 )
在需要的视图views里导入
如login.py中
# -*- coding:UTF-8 -*- from pyramid.response import Response from pyramid.view import view_config, view_defaults from pyramid.httpexceptions import HTTPFound, HTTPBadRequest, HTTPServerError, \ HTTPForbidden, HTTPUnauthorized from pyramid.security import remember, forget from myshop.lib import category, user, deforms from base import CBase ctrl = 'login' # @view_config(route_name='home', renderer='templates/mytemplate.pt') @view_defaults(route_name='/') class login(CBase): def __init__(self, request): CBase.__init__(self, request) self.request.title = u'登录' @view_config(match_param=('ctrl=%s' % ctrl, 'action=view'), renderer="login.html") # renderer="string") def view(self): deforms.deform_static.need() # 使用deform必须步骤 schema = deforms.LoginFormSchema() # 声明一个schema # 声明一个表单 form = deforms.deform.Form(schema, buttons=('submit',)) # 表单上需要哪些按钮 return { 'title':'login', 'form':form.render(), #显示表单 }
模板login.html中显示声明的表单
<%inherit file="layout/login_base.html"/> <%block name="log_c"> <div class="log_c"> ${form | n} </div> </%block>
显示如下:
后台验证表单
# -*- coding:UTF-8 -*- from pyramid.response import Response from pyramid.view import view_config, view_defaults from pyramid.httpexceptions import HTTPFound, HTTPBadRequest, HTTPServerError, \ HTTPForbidden, HTTPUnauthorized from pyramid.security import remember, forget from myshop.lib import category, user, deforms from base import CBase ctrl = 'login' # @view_config(route_name='home', renderer='templates/mytemplate.pt') @view_defaults(route_name='/') class login(CBase): def __init__(self, request): CBase.__init__(self, request) self.request.title = u'登录' @view_config(match_param=('ctrl=%s' % ctrl, 'action=view'), renderer="login.html") # renderer="string") def view(self): deforms.deform_static.need() # 使用deform必须步骤 schema = deforms.LoginFormSchema() # 声明一个schema # 声明一个表单 form = deforms.deform.Form(schema, buttons=('submit',)) # 表单上需要哪些按钮 if 'submit' in self.request.POST: try: appstruct = form.validate(self.request.POST.items()) # 对用户提交的内容进行有效性验证 except deforms.deform.ValidationFailure, e: return { 'title':'login', 'form':e.render() # 如果校验失败会提示错误信息 } user_info = user.get_user_by_name(name=appstruct['username']) # appstruct['username'] 获取表单的username if not user_info: return { 'title': 'login', 'form': form.render(), } if user_info.password != appstruct['password']: # 获取form传过来的密码 return { 'title': 'login', 'form': form.render(), } headers = remember(self.request, user_info.id) return HTTPFound(location='/', headers=headers) return { 'title':'login', 'form':form.render(), #显示表单 }
自定义验证器验证
1.用户名验证--字段级别验证 node
自定义验证器lib/validators.py
# -*- coding:UTF-8 -*- import colander import deform from myshop.lib import user def username_validator(node, value): user_info = user.get_user_by_name(name=value) if not user_info: raise colander.Invalid(node, u'用户名%s不存在' % value)
deforms.py中导入验证器
# -*- coding:UTF-8 -*- import colander import deform from js.deform import deform as deform_static import validators class LoginFormSchema(colander.MappingSchema): # 定义一个LoginFormSchema表单结构 MappingSchema表示一个映射类型 username = colander.SchemaNode(colander.Str(), # colander.SchemaNode相当于定义的Column validator = validators.username_validator # 用自定义的验证器验证数据 )
视图函数login.py中验证用户是否存在可以删除了,在验证器中验证
if 'submit' in self.request.POST: try: appstruct = form.validate(self.request.POST.items()) # 对用户提交的内容进行有效性验证 except deforms.deform.ValidationFailure, e: return { 'title':'login', 'form':e.render() # 如果校验失败会提示错误信息 } user_info = user.get_user_by_name(name=appstruct['username']) # if not user_info: # return { # 'title': 'login', # 'form': form.render(), # }
2.密码验证--表单级别验证 form
lib/validators.py声明一个password_validator
def password_validator(form, value): username = value['username'] password = value['password'] user_info = user.get_user_by_name(name=username) if user_info.password != password: raise colander.Invalid(form, u'用户名密码不正确')
视图函数login.py中声明Schema对象时应用表单验证
# -*- coding:UTF-8 -*- from pyramid.response import Response from pyramid.view import view_config, view_defaults from pyramid.httpexceptions import HTTPFound, HTTPBadRequest, HTTPServerError, \ HTTPForbidden, HTTPUnauthorized from pyramid.security import remember, forget from myshop.lib import category, user, deforms, validators from base import CBase ctrl = 'login' # @view_config(route_name='home', renderer='templates/mytemplate.pt') @view_defaults(route_name='/') class login(CBase): def __init__(self, request): CBase.__init__(self, request) self.request.title = u'登录' @view_config(match_param=('ctrl=%s' % ctrl, 'action=view'), renderer="login.html") # renderer="string") def view(self): deforms.deform_static.need() # 使用deform必须步骤 schema = deforms.LoginFormSchema(validator=validators.password_validator) # 声明一个schema # validator指定表单级别验证 # 声明一个表单 form = deforms.deform.Form(schema, buttons=('submit',), # 表单上需要哪些按钮 ) if 'submit' in self.request.POST: try: appstruct = form.validate(self.request.POST.items()) # 对用户提交的内容进行有效性验证 except deforms.deform.ValidationFailure, e: return { 'title':'login', 'form':e.render() # 如果校验失败会提示错误信息 }
此上不难看出,重复查询user_info的次数过多,如何能一次查询多次使用
定义TypeUser(),这里我直接在lib/deforms.py中定义了 也可以另写
# -*- coding:UTF-8 -*- import colander import deform from js.deform import deform as deform_static import validators from myshop.models import User from myshop.lib import user class TypeUser(object): def serialize(self, node, appstruct): # 序列化给表单 if appstruct is colander.null: # 固定用法,如果colander为null 则返回null return colander.null if not isinstance(appstruct, User): # 判断appstruct类型与数据库的User类型是否相同 raise colander.Invalid(node, u'用户类型%r不正确' % appstruct) return appstruct.name def deserialize(self, node, cstruct): # 表单反序列化给后台 if cstruct is colander.null: return colander.null if not isinstance(cstruct, basestring): raise colander.Invalid(node, u'用户%r格式不正确' % cstruct) user_info = user.get_user_by_name(name=cstruct) if not user_info: raise colander.Invalid(node, u'用户%s不存在' % cstruct) return user_info
这样appstruct['username']就是user_info数据了
validators.py中密码验证要改动
def password_validator(form, value): user_info = value['username'] password = value['password'] # user_info = user.get_user_by_name(name=username) # 如果自定义TypeUser的话 不需要多次查询数据库 if user_info.password != password: raise colander.Invalid(form, u'用户名密码不正确')
同理,login.py中查询user数据也可以删掉了
@view_config(match_param=('ctrl=%s' % ctrl, 'action=view'), renderer="login.html") # renderer="string") def view(self): deforms.deform_static.need() # 使用deform必须步骤 schema = deforms.LoginFormSchema(validator=validators.password_validator) # 声明一个schema # validator指定表单级别验证 # 声明一个表单 form = deforms.deform.Form(schema, buttons=('submit',), # 表单上需要哪些按钮 ) if 'submit' in self.request.POST: try: appstruct = form.validate(self.request.POST.items()) # 对用户提交的内容进行有效性验证 except deforms.deform.ValidationFailure, e: return { 'title':'login', 'form':e.render() # 如果校验失败会提示错误信息 } # user_info = user.get_user_by_name(name=appstruct['username']) user_info = appstruct['username'] # 直接把user数据赋值给user_info headers = remember(self.request, user_info.id) return HTTPFound(location='/', headers=headers)
OK 跟之前一样登录