该模块为验证查询参数提供了一个方便的api。
qval的Python项目详细描述
qval查询参数验证库
安装
$ pip install qval
基本用法
您可以将qval用作函数和装饰器。函数validate()
接受3个位置参数和1个名为:
# qval.pydefvalidate(# Request instance. Must be a dictionary or implement request interface.request:Union[Request,Dict[str,str]],# Dictionary of (param_name -> `Validator()` object).validators:Dict[str,Validator]=None,# Provide true if you want to access all parameters of the request in the context.box_all:bool=True,# Factories that will be used to convert parameters to python objects (param -> [callable[str] => object]).**factories,)->QueryParamValidator:
假设您有一个restful计算器,它的端点名为/api/divide
。您可以使用validate()
自动将参数转换为python对象,然后验证它们:
fromqvalimportvalidate...defdivision_view(request):""" GET /api/divide? param a : int param b : int, nonzero param token : string, length = 12 Example: GET /api/divide?a=10&b=2&token=abcdefghijkl -> 200, {"answer": 5} """# Parameter validation occurs in the context manager.# If validation fails or user code throws an error, context manager# will raise InvalidQueryParamException or APIException respectively.# In Django Rest Framework, these exceptions will be processed and result # in error codes (400 and 500) on the client side.params=(# `a` and `b` must be integers# Note: in order to get a nice error message on the client side,# you factory should raise either ValueError or TypeErrorvalidate(request,a=int,b=int)# `b` must be anything but zero.nonzero("b")# The `transform` callable will be applied to parameter before the check.# In this case we'll get `token`'s length and check if it is equal to 12..eq("token",12,transform=len))# validation starts herewithparamsasp:returnResponse({"answer":p.a//p.b})
//GET/api/divide?a=10&b=2&token=abcdefghijkl//Browser:{"answer":5}
向此终结点发送b=0将在客户端产生以下消息:
//GET/api/divide?a=10&b=0&token=abcdefghijkl{"error":"Invalid `b` value: 0."}
如果有许多参数和自定义验证器,最好使用@qval()
装饰器:
# validators.pyfromdecimalimportDecimalfromqvalimportValidator,QvalValidationError...defprice_validator(price:int)->bool:""" A predicate to validate `price` query parameter. Provides custom error message. """ifprice<=0:# If price does not match our requirements, we raise QvalValidationError() with a custom message.# This exception will be handled in the context manager and will be reraised# as InvalidQueryParamException() [HTTP 400].raiseQvalValidationError(f"Price must be greater than zero, got \'{price}\'.")returnTruepurchase_factories={"price":Decimal,"item_id":int,"token":None}purchase_validators={"token":Validator(lambdax:len(x)==12),# Validator(p) can be omitted if there is only one predicate:"item_id":lambdax:x>=0,"price":price_validator,}# views.pyfromqvalimportqvalfromvalidatorsimport*...# Any function or method wrapped with `qval()` must accept request as # either first or second argument, and parameters as last.@qval(purchase_factories,purchase_validators)defpurchase_view(request,params):""" GET /api/purchase? param item_id : int, positive param price : float, greater than zero param token : string, len == 12 Example: GET /api/purchase?item_id=1&price=5.8&token=abcdefghijkl """print(f"{params.item_id} costs {params.price}$.")...
框架特定说明
Django Rest Framework works straight out of the box. Simply add ^{
} to your views or use ^{ } inside. For Django without DRF you may need to add the exception handler to ^{
^{pr 7}$}. Qval attempts to do it automatically if ^{ } is set. Otherwise you'll see the following message: Take a look at the plain Django example here。
If you are using Flask, you will need to setup exception handlers:
^{pr 8}$Since ^{
^{pr 9}$} in Flask is a global object, you may want to curry ^{ } before usage: Check out the full Flask example在
examples/flask-example.py
中。您可以使用下面的命令运行示例:
$ PYTHONPATH=. FLASK_APP=examples/flask-example.py flask run
Similarly to Flask, with Falcon you will need to setup error handlers:
^{pr 11}$Full Falcon example可以在这里找到:
examples/falcon-example.py
。使用以下命令运行应用程序:
$ PYTHONPATH=. python examples/falcon-example.py
文档
有关详细说明和自动生成的api文档,请参阅documentation。 您还可以查看tests来了解下面的内容是如何工作的。
配置
qval支持通过配置文件和环境变量进行配置。
如果定义了DJANGO_SETTINGS_MODULE
或SETTINGS_MODULE
,则将使用指定的配置模块。否则,
所有查找都将在os.environ
中完成。
支持的变量:
QVAL_MAKE_REQUEST_WRAPPER = myapp.myfile.my_func
。自定义make_request()
函数的行为, 应用于所有传入请求,然后将结果传递给qval.qval.QueryParamValidator
。 提供的函数必须接受request
,并返回支持请求接口的对象 (见qval.framework_integration.DummyReqiest
)。
例如,下面的代码将日志记录添加到每个make_request()
调用:# app/utils.pydefmy_wrapper(f):@functools.wraps(f)defwrapper(request):print(f"Received new request: {request}")returnf(request)returnwrapper
您还需要在控制台中执行
export QVAL_MAKE_REQUEST_WRAPPER=app.utils.my_wrapper
或者将其添加到配置文件中。QVAL_REQUEST_CLASS = path.to.CustomRequestClass
。@qval()
将使用它来确定哪个参数是请求。 如果有实现qval.framework_integration.DummyRequest
接口的自定义请求类,请为其提供此变量。QVAL_LOGGERS = [mylogger.factory, ...] | mylogger.factory
。路径列表或可调用工厂的路径。 指定的可调用必须返回具有Logger
接口的对象。有关详细信息,请参见logging部分。
记录
qval在报告错误时使用名为log
的全局对象作为singleton。默认情况下,logging.getLogger
函数用作每次调用的工厂。您可以提供自己的工厂(请参见configuration)或禁用日志记录。错误消息示例:
An error occurred during the validation or inside of the context: exc `<class 'OverflowError'>`((34, 'Numerical result out of range')). | Parameters: <QueryDict: {'a': ['2.2324'], 'b': ['30000000']}> | Body : b''| Exception: Traceback (most recent call last): File "<path>/qval/qval.py", line 338, in inner return f(*args, params, **kwargs) File "<path>/examples/django-example/app/views.py", line 46, in pow_view return JsonResponse({"answer": params.a ** params.b}) OverflowError: (34, 'Numerical result out of range') Internal Server Error: /api/pow [19/Nov/2018 07:03:15]"GET /api/pow?a=2.2324&b=30000000 HTTP/1.1"500102
从qval
导入log
对象,并根据需要进行配置:
fromqvalimportlog# For instance, disable logging:log.disable()