I have an api endpoint to let user submit a form, this form has some nested objects:
class FoundForm(Model):
contact_details: FoundContactDetails
...other fields...
The embedded model of FoundContactDetails
class FoundContactDetails(EmbeddedModel):
name: str
phone_number: str
email: str
address: Optional[DetailedAddress] = None
bank_account: Optional[str] = None
bank_name: Optional[str] = None
The DetailedAddress
class DetailedAddress(EmbeddedModel):
street: str
ward: str
district: str
city: str
country: str
I want to let the user submit the form with name, phone_number, email which are required. While the address field, they can either omit it or have to provide all address object's fields.
I trying to fix by using schemas for requests validation:
async def create_found_form(form_data: FoundFormCreate) -> FoundFormRead:
form = FoundForm(**form_data.model_dump())
return await engine.save(form)
The FoundFormBase:
class FoundFormBase(BaseModel):
contact_details: FoundContactDetails #the embedded model at the top of this post
FoundFormCreate for requests validation, extend from FoundFormBase above:
class FoundFormCreate(FoundFormBase):
@field_validator('contact_details')
def validate_contact_details(cls, value):
if value.bank_account is not None and value.bank_name is None:
raise ValueError('Bank name is required if bank account is provided')
if value.address is not None:
if not all([value.address.street, value.address.ward, value.address.district, value.address.city, value.address.country]):
raise ValueError('All address fields (street, ward, district, city, country) are required if address is provided')
return value
But when user submit the form with this json using SwaggerUI which is auto-generated by FastAPI:
{
"contact_details": {
"name": "string",
"phone_number": "string",
"email": "string",
"address": {
"street": "string",
"ward": "string",
"district": "string",
"city": "string",
"country": "string"
},
"bank_account": "string",
"bank_name": "string"
}
}
It's giving error, which believe to happens on address field.
"detail": "string indices must be integers, not 'str'"
Removing bank_account or both bank_account and bank_name is ok since the validation works properly.
Thank you for reading.
How could I handle multiple nested objects, especially has some required and optional mix-in, also let ODMantic/Pydantic access objects' fields properly.
Solved: Replace EmbeddedModel with BaseModel (Pydantic)