Skip to main content

Binding form data validation framework.

Project description

xform

表单数据绑定验证框架,支持Tornado(默认)、aiohttp、sanic、flask,可自行扩展支持其它的python web框架


版本要求


目前已支持的web框架

Web框架 Python版本 备注
Tornado >= 6.0.0 python >= 3.6
Aiohttp >= 3.6.0 python >= 3.7 aiohttp对python最低支持版本3.7
Sanic >= 19.3 python >= 3.6
Flask>=2.0.1 python >= 3.6

获取安装

# 已发布在pypi的地址
pip3 install xargs
pip3 install https://github.com/marcohong/xform/archive/v0.5.0.tar.gz
# 或者使用最新版本
pip3 install git+https://github.com/marcohong/xform.git

使用示例


Flask示例,只支持2.0以上

from flask import request
from flask import Flask
from xform.httputil import HttpRequest
from xform.adapters.flask import FlaskRequest #引入Flask的适配器
from xform.form import SubmitForm
from xform import fields
HttpRequest.configure(request_proxy=FlaskRequest) # 全局设置Request的代理为FlaskRequest

app = 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'])
async def index():
    # 注意表单之前获取过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 = await form.bind(request)
    if error:
        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\=hello3

Tornado示例,更多demo请查看examples文件夹

from xform import fields
from xform import schema
from xform.form import SubmitForm

# 使用Schema可结合fields.Nested嵌套对象,支持多层嵌套对象
class UserSchema(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=lambda x: x and int(x) > 10)
        # 如果表单提交类型的是json按照字典方式传值即可,否则使用user.uid=xxx方式传值
        user=fields.Nested(UserSchema, required=False)
)

async def index():
    data, error = await form.bind(self)
  
# curl http://localhost:8888 -X POST -d "id=1&name=test&user.name=user&user.uid=2"

自定义的提示(3种方式)

'''
1.替换提示内容
'''
from xform.messages import ErrMsg
# ErrMsg.set_messages在导入fields/validator之前执行
ErrMsg.set_messages({'invalid_start_date': 'time invalid'})
from xform import fields

'''
2.使用国际化文件message.po
默认情况下是使用tornado的locale.translate('xxx')
请把messages.py定义的value翻译即可,例如:
msgid "Length must be between %s and %s" (注意%s不能少)
msgstr "长度必须在%s到%s之间"
'''
from xform import fields
# coding...

'''
3.替换提示内容,后再使用国际化,请根据第1步在导入fields/validator之前设置,
国际化文件message.po定义相对应替换后的内容即可
'''

demo

cd examples/
# test tornado
python3 test_tornado.py
# test aiohttp web
python3 test_aiohttp.py
# test sanic web
python3 test_sanic.py
...

扩展组件


自定义fields类型
import re
from typing import Optional, Any
from xform.fields import Integer, Str, VALUE_TYPES
from xform.form import SubmitForm
'''
实现_validate方法即可,如果返回值需要转换则重写get_value方法
'''
class UserField(Integer):
    # 不需要转换,因为返回值是一个缓存对象
    cvt_type = None

    def add_err_msg(self) -> None:
        self.err_msg.update({'not_exist': 'User does not exist'})

    async def _validate(self,
                        value: VALUE_TYPES,
                        attr: str,
                        data: dict) -> Optional[dict]:
        # 假设UserCache.get返回的是一个缓存对象
        data = await UserCache.get(value)
        # 错误时调用self.set_error('xxx')设置错误提示语,不需要返回内容,成功时返回内容
        if not data:
            self.set_error('not_exist')
        else:
            # 返回的是缓存对象
            return data

class OrderNOField(Str):
    regex = r'^[a-zA-Z0-9_]+$'

    def add_err_msg(self) -> None:
        self.err_msg.update({'invalid': 'Invalid order'})

    def __init__(self,
                 *,
                 length: tuple = 20,
                 **kwargs: Any):
        kwargs['length'] = length
        super().__init__(**kwargs)

    async def _validate(self,
                        value: VALUE_TYPES,
                        attr: str,
                        data: dict) -> Optional[str]:
        ret = re.match(self.regex, value)
        if not ret:
            self.set_error('invalid')
            return
        return value

# user_id是表单提交的字段(data_key是可选的,如果为空则使用user作为表单字段)
form = SubmitForm(
    user=UserField(data_key='user_id', required=True),
    order_no=OrderNOField(required=True)
)
自定义的validator验证
from xform.fields import Str
from xform.validate import Validator, ValidationError
#参考OneOf
class OneOf(Validator):
    default_message = ErrMsg.get_message('invalid_option')

    def __init__(self, choices: Union[list, tuple], error: str = None):
        self.choices = choices
        self.error = error or self.default_message

    def __call__(self, value: Union[str, int]):
        '''
        call方法实现逻辑
        '''
        if value is None or value not in self.choices:
            # 验证错误时请抛出ValidationError错误
            raise ValidationError(self.error)
        return value

# 使用validate
form = SubmitForm(
    tag=Str(required=True, validate=OneOf(('bule', 'red', 'green')))
)
其它web框架支持
'''
Tornado为例
'''
from xform.httputil import BaseRequest
class TornadoRequest(BaseRequest):
    def __init__(self, request):
        super().__init__(request)

    def get_argument(self,
                     name: str,
                     default: Any = None) -> Optional[str]:
        return self.request.get_argument(name, default=default)

    def get_from_header(self,
                        name: str,
                        default: Any = None) -> Optional[dict]:
        return self.request.request.headers.get(name, default)

    def translate(self, message: str) -> str:
        return self.request.locale.translate(message)
    # ...实现BaseRequest里面的方法,
    # 详细实现请参考xform.adapters.tornado.TornadoRequest

# 启动web服务前设置一下xform的request代理(不设置默认Tornado),以aiohttp为例
from xform.httputil import HttpRequest
from xform.adapters.aiohttp import AioHttpRequest
HttpRequest.configure(request_proxy=AioHttpRequest)
# Coding...

License


xfrom is offered under the MIT license.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

xargs-0.5.0.tar.gz (18.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

xargs-0.5.0-py3-none-any.whl (21.6 kB view details)

Uploaded Python 3

File details

Details for the file xargs-0.5.0.tar.gz.

File metadata

  • Download URL: xargs-0.5.0.tar.gz
  • Upload date:
  • Size: 18.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/4.0.1 CPython/3.9.13

File hashes

Hashes for xargs-0.5.0.tar.gz
Algorithm Hash digest
SHA256 8b2c185b4ff751304b3a07ff1e5af036e1defcd2a9b33387c1987fab783fbf31
MD5 1e0f6d808b2d2942d7257c7c16359da9
BLAKE2b-256 5f42d019eacd8c7051be4d2d049a5731531dccddc8e3fa265ed96de3c3a5770f

See more details on using hashes here.

File details

Details for the file xargs-0.5.0-py3-none-any.whl.

File metadata

  • Download URL: xargs-0.5.0-py3-none-any.whl
  • Upload date:
  • Size: 21.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/4.0.1 CPython/3.9.13

File hashes

Hashes for xargs-0.5.0-py3-none-any.whl
Algorithm Hash digest
SHA256 df6b577d63ef240cd0194db04d7835f5249d1c5c9db0aef89fcc0328b5360c45
MD5 faddcbf38349535b96bbe95b885a3f95
BLAKE2b-256 89c53e7770c54842b1788a231a59ada77eeb86c3c90d5cdefdfd4057fb78a9ee

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page