我遇到了一个关于FastAPI与SQLModel结合使用时的问题,目前还不清楚为什么无法正常工作。以下是您给出的模型代码:
class DeckBase(SQLModel):
name: str = Field(sa_column=Column(TEXT))
# 外键区域
owner_id: int = Field(foreign_key="player.id")
class Deck(DeckBase, table=True):
id: int = Field(primary_key=True)
# 关系定义区域(访问外键关联的模型)
owner: Player = Relationship(back_populates="decks")
cards: List["Card"] = Relationship(back_populates="decks", link_model=DeckCards) # ManyToMany
根据数据库表结构和SQLModel文档,您定义了一个获取所有卡组的函数:
@router.get("/", response_model=List[DeckRead])
async def read_all(offset: int = 0,
limit: int = Query(default=100, le=100),
db: Session = Depends(DbContext().get_db)):
decks = db.execute(select(Deck).offset(offset).limit(limit)).all()
return decks
其中DeckRead
类定义如下:
class DeckRead(DeckBase):
id: int
但是,在调用路由时,您遇到了以下错误:
[2024-01-02 18:37:19] [ERROR ] uvicorn.error: Exception in ASGI application
Traceback (most recent call last):
... (省略了堆栈跟踪)
fastapi.exceptions.ResponseValidationError: 3 validation errors:
{'type': 'missing', 'loc': ('response', 0, 'name'), 'msg': 'Field required', 'input': (Deck(id=1, name='Fire deck', owner_id=1),), 'url': 'https://errors.pydantic.dev/2.5/v/missing'}
{'type': 'missing', 'loc': ('response', 0, 'owner_id'), 'msg': 'Field required', 'input': (Deck(id=1, name='Fire deck', owner_id=1),), 'url': 'https://errors.pydantic.dev/2.5/v/missing'}
{'type': 'missing', 'loc': ('response', 0, 'id'), 'msg': 'Field required', 'input': (Deck(id=1, name='Fire deck', owner_id=1),), 'url': 'https://errors.pydantic.dev/2.5/v/missing'}
为什么会遇到这个问题呢?
同时让您感到困扰的是,如果使用以下代码却可以正常工作:
@router.get("/", response_model=List[DeckRead])
async def read_all(offset: int = 0,
limit: int = Query(default=100, le=100),
db: Session = Depends(DbContext().get_db)):
decks = db.get(Deck, 1)
return [decks]
问题可能在于:当您使用db.execute(select(Deck).offset(offset).limit(limit)).all()
时,返回的结果集是一个元组列表,而不是Pydantic可以理解的数据模型实例列表。FastAPI在序列化响应数据时,通过Pydantic模型进行验证,由于结果集中每个元素是SQLAlchemy对象而不是DeckRead模型的实例,因此出现了字段缺失的错误。
为了解决这个问题,您可以尝试将查询结果转换为DeckRead模型的实例列表:
decks_orm = db.execute(select(Deck).offset(offset).limit(limit)).all()
decks = [DeckRead.from_orm(deck) for deck in decks_orm]
return decks
看起来all()
函数返回的结果是FastAPI无法理解的。
谢谢!