文章目录
- SQLAlchemy Session对象如何操作数据库
- SQLAlchemy非序列化对象如何返回
- 1.问题分析
- 2.解决方案
- 方法1:使用 Pydantic 响应模型(推荐)
- 方法2:手动转换为字典(简单快速)
- 方法3:使用 SQLAlchemy 的 as_dict 方法(需在模型中添加)
- 3.完整代码示例
- 4.最佳实践建议
- 路由注册
SQLAlchemy Session对象如何操作数据库
-
模型元数据关联:
- 当创建模型实例时,SQLAlchemy 知道这个对象对应
__tablename__
指定的表 - 所有字段映射到表的列是通过类属性定义的
- 当创建模型实例时,SQLAlchemy 知道这个对象对应
-
会话操作:
-
db.add(record)
:将对象加入会话的"待处理"列表 -
db.commit()
:生成并执行SQL语句:sql
INSERT INTO user_files (id, name, type, ...) VALUES (?, ?, ?, ...)
-
-
表名确定时机:
- 开发时:通过模型的
__tablename__
静态定义 - 运行时:SQLAlchemy 通过对象的类信息确定目标表
- 开发时:通过模型的
-
为什么不需要显式指定表名:
-
ORM 的核心特性:
- 对象关系映射自动处理表关联
- 每个模型类隐式绑定到特定表
-
会话的通用性:
- 同一个
db
会话可操作多个模型 - 操作表取决于操作的模型对象类型
- 同一个
-
总结:
元素 | 作用 | 表名确定方式 |
---|---|---|
model 模型类 | 定义表结构 | 通过 __tablename__ 类属性 |
record 实例 | 携带数据 | 实例所属类决定目标表 |
db.add() | 加入会话 | 根据实例类型确定表 |
db.commit() | 执行操作 | 生成对应表的SQL语句 |
这种设计模式遵循SQLAlchemy的"Unit of Work"模式,开发者只需操作Python对象,ORM自动处理表映射和SQL生成。
SQLAlchemy非序列化对象如何返回
1.问题分析
-
SQLAlchemy 对象不是可序列化类型:
- 开发时创建的模型是 SQLAlchemy 模型实例
- FastAPI 的
JSONResponse
需要可序列化为 JSON 的 Python 基本类型(dict, list, str等)
-
__dict__
包含内部属性:- 直接使用
db_user.__dict__
会包含 SQLAlchemy 内部属性(如_sa_instance_state
) - 这些特殊属性无法被 JSON 序列化
- 直接使用
2.解决方案
方法1:使用 Pydantic 响应模型(推荐)
from pydantic import BaseModel# 定义响应模型
class UserResponse(BaseModel):id: strusername: str@router.get("/createUser")
def create_user(db:Session = Depends(get_db)):try:# ...创建用户的代码...db.commit()# 使用 Pydantic 模型转换response_data = UserResponse(id=db_user.id,username=db_user.username)return success_response(200, "创建成功", response_data.dict())except Exception as e:# ...
方法2:手动转换为字典(简单快速)
@router.get("/createUser")
def create_user(db: Session = Depends(get_db)):try:# ...创建用户的代码...db.commit()# 手动构建可序列化的字典user_data = {"id": db_user.id,"username": db_user.username}return success_response(200, "创建成功", user_data)except Exception as e:# ...
方法3:使用 SQLAlchemy 的 as_dict 方法(需在模型中添加)
# 在 User 模型类中添加
class User(Base):# ... 原有字段定义 ...def as_dict(self):return {c.key: getattr(self, c.key) for c in inspect(self).mapper.column_attrs}# 在路由中使用
@router.get("/createUser")
def create_user(db: Session = Depends(get_db)):try:# ...创建用户的代码...db.commit()return success_response(200, "创建成功", db_user.as_dict())except Exception as e:# ...
FastAPI 内部尝试序列化时:
- 检测到
db_user
不是基本类型 - 尝试调用
db_user.__dict__
- 发现
__dict__
包含不可序列化的_sa_instance_state
属性 - 最终返回空字典
{}
作为安全处理
3.完整代码示例
@router.get("/createUser")
def create_user(db: Session = Depends(get_db)):try:user = UserCreate(username="111")db_user = User()db_user.id = uuid.uuid1().hexdb_user.username = user.usernamedb.add(db_user)db.commit()# 解决方案:转换为可序列化的字典user_data = {"id": db_user.id,"username": db_user.username,# 添加其他需要返回的字段}return success_response(200, "创建成功", user_data)except Exception as e:db.rollback()return error_response(500, message="用户名至少3个字符")
4.最佳实践建议
- 始终使用 Pydantic 模型定义响应结构
- 在数据库操作后立即转换为响应模型
- 避免直接返回 ORM 对象,因为它们:
- 包含数据库会话状态信息
- 可能导致意外数据暴露
- 难以控制序列化行为
{"code": 200,"message": "创建成功","data": {"id": "","username": ""}
}