Flask extension for integration of the awesome pydantic package with Flask.
python3 -m pip install Flask-Pydantic
validate
decorator validates query and body request parameters and makes them accessible two ways:
parameter type | request attribute name |
---|---|
query | query_params |
body | body_params |
If you use annotated path URL path parameters as follows
@app.route("/users/<user_id>", methods=["GET"])
@validate()
def get_user(user_id: str):
pass
flask_pydantic will parse and validate user_id
variable in the same manner as for body and query parameters.
validate
argumentson_success_status
parameter of validate
decorator.response_many
parameter set to True
enables serialization of multiple models (route function should therefore return iterable of models).request_body_many
parameter set to False
analogically enables serialization of multiple models inside of the root level of request body. If the request body doesn't contain an array of objects 400
response is returned,400
response is returned with failure explanation.For more details see in-code docstring or example app.
Simply use validate
decorator on route function.
@app.route
decorator must precede @validate
(i. e. @validate
must be closer to the function declaration).
from typing import Optional
from flask import Flask, request
from pydantic import BaseModel
from flask_pydantic import validate
app = Flask("flask_pydantic_app")
class QueryModel(BaseModel):
age: int
class ResponseModel(BaseModel):
id: int
age: int
name: str
nickname: Optional[str]
# Example 1: query parameters only
@app.route("/", methods=["GET"])
@validate()
def get(query: QueryModel):
age = query.age
return ResponseModel(
age=age,
id=0, name="abc", nickname="123"
)
age
query parameter is a required int
curl --location --request GET 'http://127.0.0.1:5000/'
{
"validation_error": {
"query_params": [
{
"loc": ["age"],
"msg": "field required",
"type": "value_error.missing"
}
]
}
}
/?age=not_a_number
)curl --location --request GET 'http://127.0.0.1:5000/?age=abc'
{
"validation_error": {
"query_params": [
{
"loc": ["age"],
"msg": "value is not a valid integer",
"type": "type_error.integer"
}
]
}
}
curl --location --request GET 'http://127.0.0.1:5000/?age=20'
-> {"id": 0, "age": 20, "name": "abc", "nickname": "123"}
@app.route("/character/<character_id>/", methods=["GET"])
@validate()
def get_character(character_id: int):
characters = [
ResponseModel(id=1, age=95, name="Geralt", nickname="White Wolf"),
ResponseModel(id=2, age=45, name="Triss Merigold", nickname="sorceress"),
ResponseModel(id=3, age=42, name="Julian Alfred Pankratz", nickname="Jaskier"),
ResponseModel(id=4, age=101, name="Yennefer", nickname="Yenn"),
]
try:
return characters[character_id]
except IndexError:
return {"error": "Not found"}, 400
class RequestBodyModel(BaseModel):
name: str
nickname: Optional[str]
# Example2: request body only
@app.route("/", methods=["POST"])
@validate()
def post(body: RequestBodyModel):
name = body.name
nickname = body.nickname
return ResponseModel(
name=name, nickname=nickname,id=0, age=1000
)
# Example 3: both query paramters and request body
@app.route("/both", methods=["POST"])
@validate()
def get_and_post(body: RequestBodyModel,query: QueryModel):
name = body.name # From request body
nickname = body.nickname # From request body
age = query.age # from query parameters
return ResponseModel(
age=age, name=name, nickname=nickname,
id=0
)
The default success status code is 200
. It can be modified in two ways
# necessary imports, app and models definition
...
@app.route("/", methods=["POST"])
@validate(body=BodyModel, query=QueryModel)
def post():
return ResponseModel(
id=id_,
age=request.query_params.age,
name=request.body_params.name,
nickname=request.body_params.nickname,
), 201
validate
decorator@app.route("/", methods=["POST"])
@validate(body=BodyModel, query=QueryModel, on_success_status=201)
def post():
...
Status code in case of validation error can be modified using FLASK_PYDANTIC_VALIDATION_ERROR_STATUS_CODE
flask configuration variable.
kwargs
Instead of passing body
and query
to validate
, it is possible to directlydefined them by using type hinting in the decorated function.
# necessary imports, app and models definition
...
@app.route("/", methods=["POST"])
@validate()
def post(body: BodyModel, query: QueryModel):
return ResponseModel(
id=id_,
age=query.age,
name=body.name,
nickname=body.nickname,
)
This way, the parsed data will be directly available in body
and query
.Furthermore, your IDE will be able to correctly type them.
Pydantic's alias feature is natively supported for query and body models.To use aliases in response modify response model
def modify_key(text: str) -> str:
# do whatever you want with model keys
return text
class MyModel(BaseModel):
...
class Config:
alias_generator = modify_key
allow_population_by_field_name = True
and set response_by_alias=True
in validate
decorator
@app.route(...)
@validate(response_by_alias=True)
def my_route():
...
return MyModel(...)
For more complete examples see example application.
The behaviour can be configured using flask's application configFLASK_PYDANTIC_VALIDATION_ERROR_STATUS_CODE
- response status code after validation error (defaults to 400
)
Feature requests and pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change.
git clone https://github.com/bauerji/flask_pydantic.git
cd flask_pydantic
python3 -m venv venv
source venv/bin/activate
python3 -m pip install -r requirements/test.pip
git checkout -b <your_branch_name>
python3 -m pytest
Flask的一个小demo 1. 如何安装Flask包 pip install flask 其主要的依赖包:werkzeug、jinja2也会被一同install了; 2. Flask 的一个小样 app应用就是Flask的实例化对象,可以通过参数指定很多属性。详见Flask源码 from flask import Flask # Flask类的对象就是一个app应用 app = Flask(_
官网 如果你正在做接口开发,或者任何函数的开发,总会遇到需要判断参数是否正确的问题。一个一个验证不是很合理,所幸有pydantic这个包可以帮我们完成这项工作,而且是完美的完成 使用验证器装饰器可以实现对象之间的自定义验证和复杂关系。 validator装饰器 from pydantic import BaseModel, ValidationError, validator class Us
python 之 参数校验《一》 jsonschema模块 python 之 参数校验《二》 pydantic模块 python 之 参数校验《三》 marshmallow参数校验与序列化 一、背景 在api接口中,需要验证一些参数;如django、flask 有些组件支持参数的校验; 但是适用场景具有针对性,定制化程度过高,扩展性不强; 如果想自定义一些参数,则可已选用这个模块pydantic
1.首先这个错误是指:该类没有被映射到,或者说是没有被绑定 2.错误代码: ## 这一行是通过一个主键ID查到对应的所有的明细行 track_details = Track_Details.query.filter_by(track_id=params.get("id")).all() ## 这一行是把所有的明细行拿过来进行删除 db.session.delete(track_details)
flask 错误 ‘Class ‘XXX’ is not mapped’(类没有映射) 首先这个错误是指:该类没有被映射到,或者说是没有被绑定 错误代码: #这一行是通过一个主键ID查到对应的所有的明细行 track_details = Track_Details.query.filter_by(track_id=params.get("id")).all() #这一行是把所有的明细行拿过来进行删
说明 在网络交互中,为了顺利进行数据对接,通常会把结果包成一个层级字典。例如: res_dict status msg data data1 data2 这样写起来会比较费事,本篇将这样一些消息内容封装为对象,减少冗余代码。 目标 将res_dict的处理封装为对象 def get_api_input_apiregister(input_handler): input_data = inp
from typing import Optional from flask import Flask, jsonify, views, request from flask_sqlalchemy import SQLAlchemy from flask_pydantic import validate from pydantic import BaseModel from demo imp
1. models.py代码 from flask_login import UserMixin from werkzeug.security import generate_password_hash, check_password_hash class User(db.Model, UserMixin): __tablename__ = "users" id = db.Co