Nested Pydantic Model return error with FastAPI : field required (type=value_error.missing)

Viewed 9916

I got a problem using FastAPI and Pydantic. I try to return a list of records based on my Pydantic model.

Here is the SQLAlchemy Metadata :


from sqlalchemy import MetaData, Table, Column, Integer, JSON, Boolean
from sqlalchemy.sql import expression

metadata = MetaData()

CustomLayers = Table(
    "custom_layers",
    metadata,
    Column("id", Integer, primary_key=True),
    Column("data", JSON),
    Column("is_public", Boolean, default=expression.false()),
    Column("user_id", Integer),
)

Here is the "corresponding" pydantic model :

from geojson_pydantic.features import FeatureCollection
from pydantic import BaseModel

class CustomLayerResponse(BaseModel):
    is_public: bool
    data: FeatureCollection
    user_id: int
    id: int

    class Config:
        orm_mode = True

Here is my route :


@router.get("/", response_model=List[CustomLayerResponse], status_code=status.HTTP_200_OK)
async def retrieve_by_user(user_id: int):
    layer_records = await customlayers_repository.retrieve_by_user_id(user_id)
    return layer_records

Here is the Retrieve operation using the Databases library (SQL Alchemy based)


async def retrieve_by_user_id(user_id: int):
    query = CustomLayersTable.select().where(user_id == CustomLayersTable.c.user_id)
    return await database.fetch_all(query=query)

But when I run this I got bunches of ValidationError from pydantic saying that :

response -> 7 -> id
  field required (type=value_error.missing)
response -> 7 -> user_id
  field required (type=value_error.missing)
response -> 7 -> is_public
  field required (type=value_error.missing)
response -> 7 -> data
  field required (type=value_error.missing)

But what is really strange is that if I loop through the DB records returned by the ORM and manually create instances of the pydantic schema in this way :


@router.get("/", response_model=List[CustomLayerResponse], status_code=status.HTTP_200_OK)
async def retrieve_by_user(user_id: int):
    layer_records = await customlayers_repository.retrieve_by_user_id(user_id)
    response = []
    for l in layer_records:
        manual_instance = CustomLayerResponse(data=FeatureCollection.parse_raw(l.get("data")),
                                user_id=l.get("user_id"),
                                id=l.get("id"),
                                is_public=l.get("is_public"))
        response.append(manual_instance)
    return response

Then everything works just as expected and I got the List of CustomLayerResponse in response.

So I wonder what could be the problem with the "auto" validation from pydantic model (the one provided by the response_model parameter provided by FastAPI, that I set here as List[CustomLayerResponse]) ?

1 Answers

You data field should use a class that extends both FeatureCollection and BaseModel so that you can set its Config subclass field orm_true to true as well.

I haven't tested this with FeatureCollection it self but something similar happened to me.

Related