Here is the definition of my three Pydantic Model:
class SplitType(str, enum.Enum):
AUTO = "auto"
CUSTOM = "custom"
class DocumentConfigBase(BaseModel):
'''
document config detail
'''
model_config = ConfigDict(use_enum_values=True)
mode: Optional[SplitType] = Field(
default=SplitType.AUTO, validate_default=True)
chunk_size: Optional[str] = "800"
identifier: Optional[str]
text_preprocessing_rules: Dict[str, Any]
class DocumentConfigCreate(BaseModel):
'''
document config create
'''
knowledge_id: int
config: DocumentConfigBase
class SheetConfigCreate(BaseModel):
'''
need to update
'''
knowledge_id: int
pass
class ImageConfigCreate(BaseModel):
'''
need to update
'''
knowledge_id: int
pass
In the first model, I defined the mode
field as an enum type. Then I wrote the Router code.
@router.post("/config", response_model=KnowledgeConfigModel)
def create_knowledge_config(user_id: Annotated[int, Body()], config_type: Annotated[KnowledgeType, Body()], knowledge_config: Union[DocumentConfigCreate, SheetConfigCreate, ImageConfigCreate], session: Session = Depends(get_db)):
print('knowledge_config', knowledge_config)
try:
knowledge_model = KnowledgeConfigService.create(
operator=user_id, config_type=config_type,
knowledge_config=knowledge_config, session=session)
print('knowledge_model', knowledge_model)
if knowledge_model is None:
raise HTTPException(
status_code=404, detail="Config create failed")
return knowledge_model
except Exception as e:
raise HTTPException(status_code=500, detail=str(e)) from e
I used the Union type for the knowledge_config field, but when I request this API with the parameters below, I get an error: "detail": "'config'".
{
"user_id": 0,
"config_type": "document",
"knowledge_config": {
"knowledge_id": 1,
"config": {
"mode": "auto",
"chunk_size": "1000",
"identifier": "string",
"text_preprocessing_rules": {}
}
}
}
And The print statement(print('knowledge_config', knowledge_config)
) in the code outputs knowledge_config knowledge_id=1
. It seems to have lost the rest of the parameters.
mode
field is automatically set to "auto".knowledge_config: DocumentConfigCreate
, there is no error. I get all the parameters I passed, and mode
field is automatically set to "auto" as well.Therefore, I believe there is no error in my parameters; the issue likely lies in my use of the Union type, causing FastAPI to fail in parsing.
I'm new to Python, please help me fix this issue, Thanks a lot!
When you use Union to define input parameters, FastAPI should choose the right type at the validation stage. I don't know the exact algorithm, but you can think of it as FastAPI will try using these models in unknown order and FastAPI will choose first model that passes the validation as a type for this parameter.
To solve this you can use discriminated unions. This way you give to FastAPI the criteria to choose the right model.
In some cases you can solve this by adding model_config = ConfigDict(extra="forbid")
to all your models. This will force the model validation to fail if there are unknown fields. So, SheetConfigCreate
will not pass the validation when there is a field config
in the input JSON.
The following approach also helps.
Define new type: KnowledgeConfig: TypeAlias = Annotated[Union[DocumentConfigCreate, SheetConfigCreate, ImageConfigCreate], Field(union_mode='left_to_right')]
and use it instead of Union[DocumentConfigCreate, ...]