Package: xargs
xform表单数据绑定验证框架，支持Tornado(默认)、aiohttp、sanic、flask，可自行扩展支持其它的python web框架版本要求目前已支持的web框架Web框架Python版本备注Tornado >= 6.0.0python >= 3.6Aiohttp >= 3.6.0python >= 3.7aiohttp对python最低支持版本3.7Sanic >= 19.3python >= 3.6Flask>=2.0.1python >= 3.6获取安装# 已发布在pypi的地址pip3installxargs
pip3installhttps://github.com/marcohong/xform/archive/v0.5.0.tar.gz# 或者使用最新版本pip3installgit+https://github.com/marcohong/xform.git使用示例Flask示例，只支持2.0以上fromflaskimportrequestfromflaskimportFlaskfromxform.httputilimportHttpRequestfromxform.adapters.flaskimportFlaskRequest#引入Flask的适配器fromxform.formimportSubmitFormfromxformimportfieldsHttpRequest.configure(request_proxy=FlaskRequest)# 全局设置Request的代理为FlaskRequestapp=Flask(__name__)# 表单声明(也可以使用继承Form实现)form=SubmitForm(id=fields.Integer(required=True,_min=1),name=fields.Str(required=True,length=(3,20)))@app.route('/',methods=['GET','POST'])asyncdefindex():# 注意表单之前获取过body数据可能会影响get_data取不到数据(因为缓冲区数据已被flask删除)# locations:获取数据方式仅限于指定的作用域，locations可以是str或者tuple# 作用域: form/json/query/headers/cookies，组合使用例如locations=('form','json')# data, error = await self.form.bind(self, locations='json')data,error=awaitform.bind(request)iferror:return{'error':error}return{'data':data}if__name__=='__main__':app.run(port=8888)# curl -X POST http://127.0.0.1:8888/ -d '{"id": 12, "name": "hello1"}' -H "Content-type: application/json"# curl -X POST http://127.0.0.1:8888/ -d 'id=2&name=hello2'# curl http://127.0.0.1:8888/\?id\=12\&name\=hello3Tornado示例，更多demo请查看examples文件夹fromxformimportfieldsfromxformimportschemafromxform.formimportSubmitForm# 使用Schema可结合fields.Nested嵌套对象，支持多层嵌套对象classUserSchema(schema.Schema):uid=fields.Integer(required=True)name=fields.Username(required=True,length=(4,20))# group = fields.Nested(GroupSchema)form=SubmitForm(id=fields.Integer(required=True,_min=1),name=fields.Str(required=True),# when_field 当表单某一个字段的值在when_value中定义 则强制变为必填(required=True)password=fields.Password(required=False,when_field='id',when_value=lambdax:xandint(x)>10)# 如果表单提交类型的是json按照字典方式传值即可，否则使用user.uid=xxx方式传值user=fields.Nested(UserSchema,required=False))asyncdefindex():data,error=awaitform.bind(self)# curl http://localhost:8888 -X POST -d "id=1&name=test&user.name=user&user.uid=2"自定义的提示(3种方式)'''1.替换提示内容'''fromxform.messagesimportErrMsg# ErrMsg.set_messages在导入fields/validator之前执行ErrMsg.set_messages({'invalid_start_date':'time invalid'})fromxformimportfields'''2.使用国际化文件message.po默认情况下是使用tornado的locale.translate('xxx')请把messages.py定义的value翻译即可，例如:msgid "Length must be between %s and %s" (注意%s不能少)msgstr "长度必须在%s到%s之间"'''fromxformimportfields# coding...'''3.替换提示内容，后再使用国际化，请根据第1步在导入fields/validator之前设置，国际化文件message.po定义相对应替换后的内容即可'''democdexamples/# test tornadopython3test_tornado.py# test aiohttp webpython3test_aiohttp.py# test sanic webpython3test_sanic.py
...扩展组件自定义fields类型importrefromtypingimportOptional,Anyfromxform.fieldsimportInteger,Str,VALUE_TYPESfromxform.formimportSubmitForm'''实现_validate方法即可，如果返回值需要转换则重写get_value方法'''classUserField(Integer):# 不需要转换，因为返回值是一个缓存对象cvt_type=Nonedefadd_err_msg(self)->None:self.err_msg.update({'not_exist':'User does not exist'})asyncdef_validate(self,value:VALUE_TYPES,attr:str,data:dict)->Optional[dict]:# 假设UserCache.get返回的是一个缓存对象data=awaitUserCache.get(value)# 错误时调用self.set_error('xxx')设置错误提示语，不需要返回内容，成功时返回内容ifnotdata:self.set_error('not_exist')else:# 返回的是缓存对象returndataclassOrderNOField(Str):regex=r'^[a-zA-Z0-9_]+$'defadd_err_msg(self)->None:self.err_msg.update({'invalid':'Invalid order'})def__init__(self,*,length:tuple=20,**kwargs:Any):kwargs['length']=lengthsuper().__init__(**kwargs)asyncdef_validate(self,value:VALUE_TYPES,attr:str,data:dict)->Optional[str]:ret=re.match(self.regex,value)ifnotret:self.set_error('invalid')returnreturnvalue# user_id是表单提交的字段(data_key是可选的，如果为空则使用user作为表单字段)form=SubmitForm(user=UserField(data_key='user_id',required=True),order_no=OrderNOField(required=True))自定义的validator验证fromxform.fieldsimportStrfromxform.validateimportValidator,ValidationError#参考OneOfclassOneOf(Validator):default_message=ErrMsg.get_message('invalid_option')def__init__(self,choices:Union[list,tuple],error:str=None):self.choices=choicesself.error=errororself.default_messagedef__call__(self,value:Union[str,int]):'''call方法实现逻辑'''ifvalueisNoneorvaluenotinself.choices:# 验证错误时请抛出ValidationError错误raiseValidationError(self.error)returnvalue# 使用validateform=SubmitForm(tag=Str(required=True,validate=OneOf(('bule','red','green'))))其它web框架支持'''Tornado为例'''fromxform.httputilimportBaseRequestclassTornadoRequest(BaseRequest):def__init__(self,request):super().__init__(request)defget_argument(self,name:str,default:Any=None)->Optional[str]:returnself.request.get_argument(name,default=default)defget_from_header(self,name:str,default:Any=None)->Optional[dict]:returnself.request.request.headers.get(name,default)deftranslate(self,message:str)->str:returnself.request.locale.translate(message)# ...实现BaseRequest里面的方法，# 详细实现请参考xform.adapters.tornado.TornadoRequest# 启动web服务前设置一下xform的request代理(不设置默认Tornado)，以aiohttp为例fromxform.httputilimportHttpRequestfromxform.adapters.aiohttpimportAioHttpRequestHttpRequest.configure(request_proxy=AioHttpRequest)# Coding...Licensexfromis offered under the MIT license.