Fastapi: [BUG]Returning List[response_model] doesn't respect `response_model_exclude_unset `

Created on 1 Mar 2020  路  4Comments  路  Source: tiangolo/fastapi

Describe the bug

Not sure if this should be a Feature request or a bug.

When returning a List of models, the response includes "unset" key/values when response_model_exclude_unset is set to True.

To Reproduce

  1. Create a file with:
import pydantic
from fastapi import FastAPI

app = FastAPI()

class Item(pydantic.BaseModel):
    foobar: str = "foobar"
    foo: str
    bar: str = None

ALL_ITEMS = [Item(foo="foo0"), Item(foo="foo1"), Item(foo="foo2")]

@app .get("/items", response_model=List[Item], response_model_exclude_unset=True)
def get_all_items():
    return ALL_ITEMS

@app .get("/items/{item_index}", response_model=Item, response_model_exclude_unset=True)
def get_item(item_index: int):
    return ALL_ITEMS[item_index]
  1. Open the browser and call the endpoint /items.
  2. It returns a JSON with...
[
  {
    "foobar": "foobar",
    "foo": "foo0",
    "bar": null
  },
  {
    "foobar": "foobar",
    "foo": "foo1",
    "bar": null
  },
  {
    "foobar": "foobar",
    "foo": "foo2",
    "bar": null
  }
]
  1. But I expected it to return...
[
  {
    "foo": "foo0"
  },
  {
    "foo": "foo1"
  },
  {
    "foo": "foo2"
  }
]

Expected behavior

I would expect /items and /items/{item_index} to return the same representation of an item.

Screenshots

image

image

Environment

  • OS: Windows and MacOS
  • FastAPI Version: 0.47.1
  • Python version: 3.7.3

Additional context

The main thing I'm trying to achieve here is to exclude nulls when using List[MyModel]. Currently, the only workaround that I know of is to do one of the following.

  1. create a new response AllItems model and overload dict()
  2. create a middleware that strips response nulls.
  3. use an arbitrary dict (I don't want to do this)

However, given the prevalence of API's that have a /<all_items>, /<single_item> I would think that using response_model_exclude_unset or exclude_none is the more intuitive way to achieve this.

bug

Most helpful comment

Thanks for the report @Kilo59 and for the confirmation @shuvozula .

This was fixed by @juhovh-aiven on https://github.com/tiangolo/fastapi/pull/1074 :tada: :rocket:

All 4 comments

Yup, facing the same issue, where my response has "null" instead of the field being excluded entirely. The only workaround is to explicitly specify .dict(exclude_unset=True), but thats not really elegant and what response_model_exclude_unset=True is supposed to be doing under the hood.

So my model is:

class FromTo(BaseModel):
    from_: confloat(lt=9999999999.00) = None
    to_: confloat(lt=9999999999.00) = None

    class Config:
        allow_population_by_field_name = True
        fields = {
            'from_': 'from',
            'to_': 'to'
        }

and the route looks like:

@router.post(
    '/fromto',
    response_model=FromTo,
    response_model_exclude_unset=True
)
async def from_to() -> Dict:
  return FromTo()  # not setting from_ and to_, so both should default to None

but the response looks like:

{
    "from": null,
    "to": null
}

where I'm expecting the response to be empty like:

{}

Thanks for the report @Kilo59 and for the confirmation @shuvozula .

This was fixed by @juhovh-aiven on https://github.com/tiangolo/fastapi/pull/1074 :tada: :rocket:

Thank you!!!! I can confirm this issue is now resolved on my end and the from/to fields are not appearing in the response if not set.

Thanks for reporting back @shuvozula ! :rocket:

And thanks @Kilo59 for coming back to close the issue :+1:

Was this page helpful?
0 / 5 - 0 ratings