我遵循此答案的方法2,以便能够使用fastapi结合附加数据上传多个文件。运行良好。
开始实施附加数据的处理(包括使用 pydantic 的验证)后,我面临一个问题:
我的自定义BaseModel
在直接使用模型类时可以正常工作,但是当通过 FastAPI 和
field_validator
使用它时,它无法按预期工作。关键点是我想使用python Depends()
并且我希望能够在附加数据(查询参数)中使用枚举的
Enum
。因此,我使用自定义验证器仅允许枚举中存在的名称。当我手动初始化模型时,验证按预期工作:
names
将此与 FastAPI 应用程序结合显示出意外的行为:不考虑 field_validator。相反,使用模型类的默认行为。
服务器代码:
from enum import Enum
from pydantic import BaseModel, field_validator, ValidationInfo, ValidationError
class VehicleSubSystems(Enum):
A = "A Verbose"
B = "B Verbose"
class EvaluationArguments(BaseModel):
vehicle_sub_system: VehicleSubSystems
@field_validator("vehicle_sub_system", mode='before')
@classmethod
def validate_vehicle_sub_system(cls, vehicle_sub_system: str, _info: ValidationInfo) -> VehicleSubSystems:
""" Allows using the enum names instead of the values """
try:
return VehicleSubSystems[vehicle_sub_system]
except KeyError:
raise ValueError(f"Can not find vehicle subsystem '{vehicle_sub_system}'. "
f"Allowed values: {[e.name for e in VehicleSubSystems]}")
def test_validation_is_performed():
""" Test that the validation is performed """
EvaluationArguments(vehicle_sub_system="A")
try:
EvaluationArguments(vehicle_sub_system="DOES_NOT_EXIST")
except ValidationError:
print("Test passed")
else:
print("Test failed")
if __name__ == '__main__':
test_validation_is_performed()
# prints "Test passed" as expected
客户端代码:
import uvicorn
from typing import List
from fastapi import FastAPI, File, Depends, UploadFile
app = FastAPI()
def create_args(vehicle_sub_system: str):
return EvaluationArguments(vehicle_sub_system=vehicle_sub_system)
@app.post("/process-works")
def process_works(files: List[UploadFile] = File(...), eval_args: EvaluationArguments = Depends(create_args)):
return f"Got {len(files)} files and {eval_args}"
@app.post("/process-fails")
def process_fails(files: List[UploadFile] = File(...), eval_args: EvaluationArguments = Depends()):
return f"Got {len(files)} files and {eval_args}"
if __name__ == '__main__':
uvicorn.run(app, host="0.0.0.0", port=8000)
import requests
if __name__ == '__main__':
url = 'http://127.0.0.1:8000'
files = [('files', open('d:/temp/a.txt', 'rb')), ('files', open('d:/temp/b.txt', 'rb'))]
params = {"vehicle_sub_system": "A"}
print("Calling process-works")
resp = requests.post(url=f"{url}/process-works", params=params, files=files)
print(resp.json())
print("Calling process-fails")
resp = requests.post(url=f"{url}/process-fails", params=params, files=files)
print(resp.json())
# Output
# Calling process-works
# Got 2 files and vehicle_sub_system=<VehicleSubSystems.A: 'A Verbose'>
# Calling process-fails
# {'detail': [{'type': 'enum', 'loc': ['query', 'vehicle_sub_system'], 'msg': "Input should be 'A Verbose' or 'B Verbose'", 'input': 'A', 'ctx': {'expected': "'A Verbose' or 'B Verbose'"}}]}
端点显示了预期的行为,但仅当使用单独的依赖项
process-works
模仿模型类的直接使用时。Depends(create_args)
端点(使用
process-fails
)显示了问题。我希望 Depends()
只是让 FastAPI 调用模型类的 init 方法并按预期使用验证。但不知怎的,它只是忽略了它。我不明白为什么,也许有人可以解释这里发生了什么,以及是否有没有解决方法的解决方案?
Depends()
将检查
Depends(x)
中的 args
,并填写参数。因此,在这种情况下,您应该将 x
传递给 x
。参考:https://fastapi.tiangolo.com/tutorial/dependency/classes-as-dependency/如果你不喜欢写Depends
函数,也许你可以使用
create_args
。参考:https://fastapi.tiangolo.com/tutorial/body-multiple-params/
Body()
# client
import requests
if __name__ == '__main__':
url = 'http://127.0.0.1:8000'
params = {'fff': 'A'}
resp = requests.get(
url=f"{url}/ggg/",
params=params,
)
print(resp.json())
resp = requests.post(
url=f"{url}/ppp/",
json=params,
)
print(resp.json())
'''
{'fff': 'A Verbose'}
{'fff': 'A Verbose'}
'''