Search code examples
pythonfastapipydantic

Python API Patch updates all fields instead of just the given


So my issue is when creating a patch request to post which will update title and content but when sending, the patch request updates all optional fields to the defaults:

post- it's class:

class Post(BaseModel):
  title: str
  content: str
  published: bool = True
  rating: Optional[bool] = None

post stored in memory:

[{"title": "title",
  "content": "stuff", 
  "published": False,
  "rating": True,
  "id": 1}]

json sent:

{
"title": "updated title",
"content": "stuffyy"
}

post received:

{
"data": {
    "title": "updated title",
    "content": "stuffyy",
    "published": true,
    "rating": null,
    "id": 1
   }
}

and the python code:

@app.patch("/posts/{id}")
def update_post(id: int, post: Post):
    index = find_index_post(id)
    if index == None:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=f"post with id: '{id}' does not exist, hence cannot be updated")
    post_dict = post.dict()
    post_dict['id'] = id
    my_posts[index] = post_dict
    return {"data": post_dict}

probably out of my depth here


Solution

  • You need to exclude those fields that are not required to partially update(patching), currently on your Post schema published, rating has default values like True(true) and None(null) because you are referring post: Post here def update_post(id: int, post: Post):

    class Post(BaseModel):
      title: str
      content: str
      published: bool = True        #  <--------default to true
      rating: Optional[bool] = None #  <--------default to null
    

    So you can do this way with exclude while making post to the dictionary.

    post_dict = post.dict(exclude_unset=True)
    

    OR

    post_dict = post.dict(exclude={'published', 'rating'})