2

Assuming the following:

class User(BaseModel):
    name : str
    bio  : Optional[str]

class UpdateUser(BaseModel):
    name = Optional[str] = Field(None)
    bio  = Optional[str] = Field(None)

@app.put("/users/{id}", response_model=User)
async def put_user(pk:int, payload:UpdateUser) -> User:
    ...

If omitted fields are simply defaulted to None in payload, how can I tell the difference between a client omitting the field (because they don't want to update it) vs explicitly setting the field to None?

Restated a different way: How do I implement an API that doesn't require every field to be specified on an update, but is still able to differentiate between omitted fields and an explicit update of a field to None (when appropriate)?

odigity
  • 7,568
  • 4
  • 37
  • 51
  • Make bio being str with default being empty string - then user removing the bio would set it back to empty string. The bio being None doesn't make much sense conceptually - it's "optional" for user, but when displaying any edit form it's some text field and all user can do is remove the text - so just empty string, not None – h4z3 Jul 11 '23 at 14:55
  • @h4z3 It's a contrived example, and maybe an optional string wasn't the best choice, but the question stands - what if you need to differentiate between those two very real and useful cases? Also, even in the empty string example, that still leaves the problem of differentiating between omission and explicit empty string... – odigity Jul 11 '23 at 14:58
  • Can you remove attributes from `UpdateUser` that you don't want to process, then an attribute set to None would indicate that preference? – JonSG Jul 11 '23 at 15:05
  • Please have a look at [this answer](https://stackoverflow.com/a/73261442/17865804) – Chris Jul 11 '23 at 15:10
  • 2
    That is exactly what the `exclude_unset` parameter in the `dict` method (`model_dump` in v2) is for. If you want to inspect the model rather than dumping it to a dictionary, you can also check its `__fields_set__` attribute (`__pydantic_fields_set__` in v2). How you should proceed depends on what exactly you want to _do_ with that `payload` object, once you have it. – Daniil Fajnberg Jul 11 '23 at 18:15

0 Answers0