10

FastAPI shows that you can set response_model_exclude_none=True in the decorator to leave out fields that have a value of None: https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter

I would like to do this, but the None field I want to exclude is nested within the parent response model. I.e.

class InnerResponse(BaseModel):
    id: int
    name: Optional[str] = None

class Response(BaseModel):
    experience: int
    prices: List[InnerResponse]


@app.post("/dummy", response_model=apitypes.Response, response_model_exclude_none=True)
async def backend_dummy(payload: apitypes.Request):
...

However, when I get a response back, it the "prices" list here still has InnerResponses that have "name": null.

Is there a way to apply the exclude rule on nested models?

maccam912
  • 792
  • 1
  • 7
  • 22
  • 1
    FastAPI (or Pydantic) will remove the `None` (or `null`) values from **`response_model`** (if specified) if ***`response_model_exclude_none`*** is `True`. – JPG Oct 07 '20 at 17:56
  • BTW, I tried to reproduce the behavior using [this example from the official doc](https://fastapi.tiangolo.com/tutorial/body-nested-models/#nested-models), but, I have got the expected response, which is, a response without any `None` (or `null`) values – JPG Oct 07 '20 at 17:58
  • I recommend to double-check your code and still issue persists, please do add a ***minimal verifiable example*** @maccam912 – JPG Oct 07 '20 at 18:00
  • Thanks @ArakkalAbu for testing it. I made a new project with the code and you're right, it works as expected. My problem was code outside of this chunk that was adding that field BACK IN. Another FastAPI calling the endpoint that I hadn't set response_model_exclude_none=True on. – maccam912 Oct 08 '20 at 13:12

2 Answers2

6

For anyone who finds this while searching: The code above works fine, but my issue was another endpoint outside of this code block that did not have the response_model_exclude_none=True set on it. Every endpoint that needs to exclude those "None" values needs to have that set.

maccam912
  • 792
  • 1
  • 7
  • 22
  • I can confirm that a route's response excluede unset attributes if both `response_model=MyResponse` and `response_model_exclude_none=True` are set. – Ken Jiiii Apr 06 '23 at 07:46
4

A possibility will be to create a class that inherits from BaseModel and override the dict method:

from pydantic import BaseModel

class AppModel(BaseModel):

  def dict(self, *args, **kwargs):
    if kwargs and kwargs.get("exclude_none") is not None:
      kwargs["exclude_none"] = True
      return BaseModel.dict(self, *args, **kwargs)

Now, create the classes from AppModel:

class InnerResponse(AppModel):
  id: int
  name: Optional[str] = None

class Response(AppModel):
  experience: int
  prices: List[InnerResponse]
Adrian Mole
  • 49,934
  • 160
  • 51
  • 83
jemutorres
  • 79
  • 5
  • That won't work, since FastAPI is going to inject a value of `False` for `exclude_none`. So you'll have to manually call `response.dict()` in all your routes as well. – HHK Nov 09 '21 at 22:20