Starlette中sqlalchemy.exc.ArgumentError报错排查解决
报错原因
- 根因:传入
query()方法的PersonDetail是Pydantic数据校验类,不是SQLAlchemy/SQLModel可识别的数据库表映射模型。ORM查询方法仅接受继承自ORM declarative base的表模型、列表达式或合法FROM子句对象,纯Pydantic类不具备数据库表映射能力,无法作为查询目标。 - 附带的代码错误:
- 导入完全错误:
get.py中从GUI库tkinter.tix导入的Select和ORM查询无关,属于IDE自动补全导错包;同时重复从db和sqlmodel导入Session,会产生命名覆盖。 schemas.py中从Python语法解析模块lib2to3.pytree导入的Base无任何作用,同样是导错包;且__tablename__是ORM表模型专属属性,写在Pydantic类上不会产生任何表映射效果。- 会话生命周期错误:模块加载时就初始化全局数据库会话,在Starlette的多请求并发场景下会出现连接复用冲突、数据脏读、连接泄漏问题。
- 导入完全错误:
修复步骤
- 拆分模型职责:将数据库表映射模型和Pydantic校验模型分离,ORM模型负责和数据库交互,Pydantic模型负责请求/响应的数据校验序列化。
- 清理所有错误导入,修正会话使用方式,按请求创建会话,用完自动释放。
修正后的代码示例
1. 数据库表模型(新建models.py,存放所有ORM表映射)
from sqlmodel import SQLModel, Field # 继承SQLModel并设置table=True才是合法的数据库表模型 class PersonDetail(SQLModel, table=True): __tablename__ = "PersonDetail" # 和你原有表名保持一致即可 # 必须定义主键字段,否则SQLModel无法完成表映射 id: int | None = Field(default=None, primary_key=True) name: str
2. 修正schemas.py(仅存放Pydantic校验模型)
from pydantic import BaseModel # 建议和ORM模型做命名区分,避免导入时混淆 class PersonDetailResp(BaseModel): name: str class Config: # 开启后支持直接从ORM模型对象提取数据序列化 from_attributes = True
3. 修正get.py业务代码
from starlette.requests import Request from starlette.responses import JSONResponse from db import engine # 导入的是ORM表模型,不是Pydantic schema from models import PersonDetail from sqlmodel import Session, select def GetMethod(request: Request): # 每个请求单独创建会话,上下文管理器会自动处理会话提交、关闭 with Session(bind=engine, expire_on_commit=False) as local_session: # SQLModel推荐使用select语法查询,避免导错Query相关包 query_stmt = select(PersonDetail) result = local_session.exec(query_stmt).all() # 序列化后返回JSON响应 return JSONResponse([item.model_dump() for item in result])
补充说明:如果是首次运行,需要在Starlette应用启动事件中执行
SQLModel.metadata.create_all(engine),自动创建对应数据库表;如果已有对应数据表,跳过该步骤即可。
内容的提问来源于stack exchange,提问作者SPMK
相关产品推荐
相关产品推荐

