FastAPI中SQLModel返回JSON时丢失子列表数据问题排查
问题原因
Relationship是SQLAlchemy的ORM关联字段,SQLModel默认不会将这类字段纳入Pydantic的序列化范围——尽管SQLAlchemy会在Session内加载关联数据(所以你能打印出values),但FastAPI使用response_model=TableRecord时,会严格按照模型定义的数据字段来序列化,而Relationship字段不属于这个范畴,因此返回的JSON里会缺失该字段。
解决方案
方案1:创建专用响应模型(推荐)
定义独立的响应模型,显式包含需要序列化的关联字段,同时避免循环引用和ORM细节泄露:
from typing import List, Optional from sqlmodel import SQLModel from datetime import datetime # 先定义子模型的响应结构 class TableRecordValueResponse(SQLModel): id: Optional[int] column_id: int value: str updated_on: Optional[datetime] updated_by: int # 定义父模型的响应结构,包含关联的values字段 class TableRecordResponse(SQLModel): record_key: Optional[int] table_id: int created_by: int values: List[TableRecordValueResponse] = []
然后修改接口,使用新的响应模型,并主动加载关联数据(避免懒加载潜在问题):
from sqlalchemy.orm import selectinload @table_records_router.get("/table_records/{record_key}", response_model=TableRecordResponse) def get_table_record(record_key: int): with Session(engine) as session: # 使用selectinload主动加载关联的values数据 statement = select(TableRecord).options(selectinload(TableRecord.values)).where(TableRecord.record_key == record_key) table_record = session.exec(statement).first() if not table_record: raise HTTPException(status_code=404, detail=f"TableRecord with key {record_key} not found") return table_record
方案2:修改原ORM模型,让Relationship字段可序列化
如果不想创建新模型,可以修改TableRecord的values字段定义,将其同时标记为Pydantic可序列化的字段:
class TableRecord(SQLModel, table=True): __tablename__: str = "table_record" record_key: Optional[int] = Field(default=None, primary_key=True) table_id: int created_by: int # 通过Field显式定义为Pydantic字段,并关联ORM关系 values: list["TableRecordValue"] = Field( default=[], sa_column=Relationship(back_populates="table_record") )
注意:这种方式可能会引入循环引用问题,需要确保TableRecordValue的定义能被正确识别,同时查询时依然需要主动加载关联数据(用selectinload或joinedload)。
额外注意点
- 务必主动加载关联数据:如果只使用基础查询,SQLAlchemy默认会用懒加载(lazy="select"),在Session关闭后访问
values会报错,且序列化时可能无法正确获取数据。使用selectinload(适合一对多)或joinedload(适合内连接)可以提前加载关联数据。
内容的提问来源于stack exchange,提问作者RogerKint
相关产品推荐
相关产品推荐

