FastAPI does not honour validator pre=True #9853
-
First Check
Commit to Help
Example Codefrom fastapi import Depends, FastAPI, Request
from pydantic import BaseModel, validator
class Params(BaseModel):
ids: list[str] = []
@validator("ids", pre=True)
def split_string(cls, val):
print("validator: received", val.__repr__())
return val.split(",") if isinstance(val, str) else ["boo"]
app = FastAPI()
@app.get("/test")
def test(request: Request, params: Params = Depends()):
print(">> via fastapi:", params)
print(">> directly:", Params(**dict(request.query_params)))
return paramsDescriptionRun the above code with Server output: The validator should run before If I construct the model manually, as per the However, when fastapi constructed the The root validator has the same behaviour. I also tried overriding I'm aware of some workarounds (e.g. using a method to construct the class) but there are various other downsides to them. I'd much rather get it working purely via Operating SystemWindows Operating System DetailsNo response FastAPI Version0.85.1 Python Version3.10.8 Additional ContextPydantic 1.10.7 |
Beta Was this translation helpful? Give feedback.
Replies: 3 comments 6 replies
-
|
I think you miss interpreted the outputs. Pydantic is working completely as it should. The reason why it defaulted to empty list at first is because it was never initialized inside the request body so it never triggered the validator. Since it was not assigned a value, it will be defaulted to empty list which triggers the validator that then converts basically this took place when the request body was empty def test(request: Request, params = Params(ids=[])):It is like the default value is injected during initialization and not after. Side note: class Params(BaseModel):
ids: list[str] = Field(default_factory=list) |
Beta Was this translation helpful? Give feedback.
-
|
@michaelspori experiencing something similar, did you ever get a resolution here? |
Beta Was this translation helpful? Give feedback.
-
|
Using Pydantic Since 0.115.0 FastAPI you can officially use Pydantic models to declare Query parameters. from fastapi import Query, FastAPI, Request
from pydantic import BaseModel, field_validator
class Params(BaseModel):
ids: list[str] = []
@field_validator("ids", mode="before")
@classmethod
def split_string(cls, val):
print("validator: received", val.__repr__())
if isinstance(val, list) and len(val) == 1 and isinstance(val[0], str):
val = val[0]
return val.split(",") if isinstance(val, str) else ["boo"]
app = FastAPI()
@app.get("/test")
def test(request: Request, params: Params = Query()):
print(">> via fastapi:", params)
print(">> directly:", Params(**dict(request.query_params)))
return params
Output: There is currently a limitation with this approach - you can't use multiple Query parameter models and you can't combine Query parameter model with single Query parameters in one endpoint. |
Beta Was this translation helpful? Give feedback.
Using Pydantic
BaseModelwithDependswas never officially supported in FastAPI. It partially works, but not always as expected.Since 0.115.0 FastAPI you can officially use Pydantic models to declare Query parameters.
To do this, you should replace
params: Params = Depends()withparams: Params = Query().You should also modify your validator to expect list of strings, not just string - since parameter is annotated as
list, FastAPI will extract it as list and pass to your validator.