動かざることバグの如し

近づきたいよ 君の理想に

fastapiでvalue is not a valid dictエラーになる

環境

  • fastapi v0.75

状況

以下のようなエラーが出て動かない

pydantic.error_wrappers.ValidationError: 1 validation error for User
response -> 0
  value is not a valid dict (type=type_error.dict)

main.pyコードは以下 よくあるコードなので抜粋のみ

from fastapi import Depends, FastAPI
from sqlalchemy.orm import Session

from . import models, schemas
from .database import SessionLocal, engine

models.Base.metadata.create_all(bind=engine)

app = FastAPI()

def get_db():
  db = SessionLocal()
  try:
    yield db
  finally:
    db.close()

@app.get("/users", response_model=list[schemas.User])
def all_fetch(db: Session = Depends(get_db)):
  users = db.query(models.User).all()
  return users

でschema.pyが以下

from pydantic import BaseModel

class User(BaseModel):
  id: int
  email: str

対処法

schema.pyに追記して、 orm_mode = True にする必要がある。

追記したコードが以下

from pydantic import BaseModel

class User(BaseModel):
  id: int
  email: str

  class Config:
    orm_mode = True

なぜ

response_model=list[schemas.User] に書いてあるように、レスポンスは辞書(dict)を期待している。

が、実際にはSQLAlchemyのモデルが返ってきてしまっているので invalid となりエラーになってしまう

動いたり動かなかったりする

ここがfastapi初心者あるあるで原因がよくわかってないからコードのどこが原因でエラーになるのかが分かりづらい。

原因にもあるようにresponse_modelでdictを指定しているのに反しているからエラーになっているので指定しなければエラーにならない

@app.get("/users")
def all_fetch(db: Session = Depends(get_db)):
  users = db.query(models.User).all()
  return users

また、結果として辞書型になっていればいいので変換すると一応動いてしまう

# 動くが、よくないやり方
@app.get("/users")
def all_fetch(db: Session = Depends(get_db)):
  users = db.query(models.User).all()
  return return [ x.__dict__ for x in users]

ちゃんと定義はschema.pyに書こう

参考リンク