Pydantic input model for partial updates

Viewed 9948

I am using Pydantic to validate data inputs in a server. Pydantic models:

  • User: for common fields
  • UserIn: user input data to create new account
  • UserInDB: to hash password and include extra fields like created_at
  • UserOut: to output created/updated user data

Now how can I utilize the model UserIn for user account partial updates? so that None fields are excluded. Or do I have to rewrite it again and make every field optional?

class User(BaseModel):

    name_first :          str = Field(...)
    name_last :           Optional[str] = None
    mobile :              int = Field(..., description="It has to be 8 digits and starts with either 9 or 7", example="99009900")
    
    email :               Optional[EmailStr] = None
    
    gender:               Literal['m', 'f'] = Field(..., example="m")
    birth_date:           datetime.date
    preferred_language :  Literal['ar', 'en'] = Field(..., example="ar")
    newsletter :          bool = Field(...)


    @validator('mobile')
    def number_has_to_start_with_9_or_7(cls, v):
        if str(v)[:1] !="9" and str(v)[:1] !="7":
            raise ValueError('Mobile number must start with 9 or 7')
        if len(str(v)) !=8:
            raise ValueError('Mobile number must be 8 digits')
        return v


class UserIn(User):
    password: str = Field(...)

class UserInDB(UserIn):
    mobile_otp:           int = Field(...)
    bitrole:              int = Field(...)
    created_at:           datetime.datetime
    updated_at:           datetime.datetime

class UserOut(User):
    id:                   int
    mobile_otp:           int
    bitrole:              int
    mobile_confirmed :    bool
    email_confirmed :     bool
    disabled :            bool
    created_at:           datetime.datetime
    updated_at:           datetime.datetime

    class Config:
        orm_mode = True
1 Answers

Unfortunately this is a problem that has been already faced by quite a lot of people (me included).

There is no simple way of handling it out of the box and as far as I know.

Here are some solutions proposed to bypass the problem, although not completely, on github

https://github.com/samuelcolvin/pydantic/issues/990#issuecomment-645961530

MY SOLUTION

I use pydantic with fastapi and partial updates of resources are quite common. Due to the limitation of pydantic I ask the user to resubmit all the values, filling correctly the pydantic model and then update all the fields that can be updated.

It's not ideal, I know, but it seems to work

UPDATE

I've found another possible solution. Basically, retrieve the old data, update it, and write the updated data (much better than my solution).

See fastapi docs https://fastapi.tiangolo.com/tutorial/body-updates/#partial-updates-with-patch

Related