33

this is my database schema.

enter image description here

I defined my Schema like this:

from pydantic import BaseModel

class Userattribute(BaseModel):
    name: str
    value: str
    user_id: str
    id: str

This is my model:

class Userattribute(Base):
    __tablename__ = "user_attribute"

    name = Column(String)
    value = Column(String)
    user_id = Column(String)
    id = Column(String, primary_key=True, index=True)

In a crud.py I define a get_attributes method.

def get_attributes(db: Session, skip: int = 0, limit: int = 100):
    return db.query(models.Userattribute).offset(skip).limit(limit).all()

This is my GET endpoint:

@app.get("/attributes/", response_model=List[schemas.Userattribute])
def read_attributes(skip: int = 0, limit: int = 100, db: Session = Depends(get_db)):
    users = crud.get_attributes(db, skip=skip, limit=limit)
    print(users)
    return users

The connection to the database seems to work, but a problem is the datatype:

pydantic.error_wrappers.ValidationError: 7 validation errors for Userattribute
response -> 0
  value is not a valid dict (type=type_error.dict)
response -> 1
  value is not a valid dict (type=type_error.dict)
response -> 2
  value is not a valid dict (type=type_error.dict)
response -> 3
  value is not a valid dict (type=type_error.dict)
response -> 4
  value is not a valid dict (type=type_error.dict)
response -> 5
  value is not a valid dict (type=type_error.dict)
response -> 6
  value is not a valid dict (type=type_error.dict)

Why does FASTApi expect a dictionary here? I don´t really understand it, since I am not able to even print the response. How can I fix this?

2 Answers 2

79

Pydantic 2 changed how models gets configured, so if you're using the most recent version of Pydantic, see the section named Pydantic 2 below.

SQLAlchemy does not return a dictionary, which is what pydantic expects by default. You can configure your model to also support loading from standard orm parameters (i.e. attributes on the object instead of dictionary lookups):

class Userattribute(BaseModel):
    name: str
    value: str
    user_id: str
    id: str

    class Config:
        orm_mode = True

You can also attach a debugger right before the call to return to see what's being returned.

Since this answer has become slightly popular, I'd like to also mention that you can make orm_mode = True the default for your schema classes by having a common parent class that inherits from BaseModel:

class OurBaseModel(BaseModel):
    class Config:
        orm_mode = True


class Userattribute(OurBaseModel):
    name: str
    value: str
    user_id: str
    id: str

This is useful if you want to support orm_mode for most of your classes (and for those where you don't, inherit from the regular BaseModel).

Pydantic 2

Pydantic 2 has replaced the internal Config class with a model_config field:

from pydantic import ConfigDict

class OurBaseModel(BaseModel):
    model_config = ConfigDict(from_attributes=True)

This works in the same way as the old orm_mode.

2
  • 4
    Thanks in my case I had got code from another dev and he had typo class config: Commented Feb 6, 2022 at 5:46
  • 2
    Using the orm_mode in my parent class fixed it... THANK YOU
    – joeyagreco
    Commented Nov 30, 2022 at 20:57
1

This error is caused by two things:

  1. The reponse_model parameter in the path operation decorator, which defines the type/shape of response to be returned. Removing this will eliminate the errors you see, as it will remove the validation against what is being returned.

  2. The internal Config class that is missing in your Pydantic schemas.

Make sure to add the Config class to avoid this problem, or at worst, remove the response_model parameter (which I doubt anyone would consider). Example is:

class ItemBase(BaseModel):
    title: str
    description: Union[str, None] = None

    class Config:
        orm_mode = True

Adding this class allows Pydantic model to read data in non-dictionary format, thereby allowing you to return database model.

Checkout the fastAPI documentation for more

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.