之前我在 Flask 中使用了 marshmallow 库。前段时间我尝试过 FastAPI 和 Pydantic。乍一看,
pydantic
似乎与 masrhmallow
相似,但仔细观察它们却有所不同。对我来说,它们之间的主要区别是来自 marshmallow
的 post_load方法。我在
pydantic
中找不到任何类似物。
post_load
是后处理方法的装饰器。使用它我可以自己处理返回对象,可以做任何我想做的事:
class ProductSchema(Schema):
alias = fields.Str()
category = fields.Str()
brand = fields.Str()
@post_load
def check_alias(self, params, **kwargs):
"""One of the fields must be filled"""
if not any([params.get('alias'), params.get('category'), params.get('brand')]):
raise ValidationError('No alias provided', field='alias')
return params
此外它不仅用于验证。代码示例仅供直观理解,请勿分析,我刚刚发明的。
所以我的问题是:
post_load
中是否有 pydantic
的类似物?
这并不明显,但
pydantic's
验证器返回字段的值。
有两种方法处理
post_load
转换: validator
和
root_validator
.
validator
获取字段值作为参数并返回其值。
root_validator
相同,但操纵整个对象。
from pydantic import validator, root_validator
class PaymentStatusSchema(BaseModel):
order_id: str = Param(..., title="Order id in the shop")
order_number: str = Param(..., title="Order number in chronological order")
status: int = Param(..., title="Payment status")
@validator("status")
def convert_status(cls, status):
return "active" if status == 1 else "inactive"
@root_validator
def validate_order_id(cls, values):
"""Check order id"""
if not values.get('orderNumber') and not values.get('mdOrder'):
raise HTTPException(status_code=400, detail='No order data provided')
return values
默认情况下,
pydantic
将验证器作为后处理方法运行。对于预处理,您应该使用带有 pre
参数的验证器:
@root_validator(pre=True)
def validate_order_id(cls, values):
"""Check order id"""
# some code here
return values
在 Pydantic v2 验证器中迁移:
validator
到 field_validator
和 root_validator
到 model_validator
。
@field_validator('status')
@classmethod
def convert_status(cls, status: int):
return "active" if status == 1 else "inactive"
@model_validator(mode='after')
@classmethod
def validate_order_id(cls, values):
"""Check order id"""
if not values.get('orderNumber') and not values.get('mdOrder'):
raise HTTPException(status_code=400, detail='No order data provided')
return values
对于后处理或预处理,请使用
mode
参数。
是的,您可以使用 Pydantic 的
@validator
decorator 进行预加载、后加载、模型验证等。
这是一个加载后示例
from pydantic import validator
class Person(BaseModel):
first_name: str
second_name: str
@validator("first_name")
def make_it_formal(cls, first_name):
return f"Mr. {first_name.capitalize()}"
p = Person(first_name="egvo", second_name="Example")
p.first_name
Out: Mr. Egvo
或者,您也可以覆盖
__init__
并在那里对实例进行后处理:
from pydantic import BaseModel
class ProductSchema(BaseModel):
alias: str
category: str
brand: str
def __init__(self, *args, **kwargs):
# Do Pydantic validation
super().__init__(*args, **kwargs)
# Do things after Pydantic validation
if not any([self.alias, self.category, self.brand]):
raise ValueError("No alias provided")
尽管这种情况发生在 Pydantic 的验证之外。