SQLAlchemy ORM 入门教程
1. 安装 SQLAlchemy
pip install sqlalchemy # 使用pip指令安装必要包
2. 创建数据库连接与基础配置
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker# 创建数据库引擎(这里以 SQLite 为例,数据库文件为 test.db)
engine = create_engine('sqlite:///test.db', echo=True)# 创建基类
Base = declarative_base()# 创建会话类
SessionLocal = sessionmaker(bind=engine)
说明:
create_engine
创建数据库连接引擎,echo=True
可以打印执行的 SQL,方便调试。declarative_base()
用于声明模型基类。sessionmaker
用于创建数据库会话,后续操作通过 session 进行。
易错点:
- 数据库连接字符串格式不对会导致连接失败,注意不同数据库连接字符串不同。
sessionmaker
必须绑定engine
,否则无法操作数据库。
3. 定义 ORM 模型(创建表结构)
from sqlalchemy import Column, Integer, Stringclass User(Base):__tablename__ = 'users' # 表名id = Column(Integer, primary_key=True, index=True)name = Column(String(50), nullable=False)age = Column(Integer)def __repr__(self):return f"<User(id={self.id}, name={self.name}, age={self.age})>"
说明:
User
类继承自Base
,代表数据库中的一张表。所有继承Base的类都会被存储到Base的metadata中。__tablename__
指定表名。Column
定义字段类型和约束。primary_key=True
表示主键。nullable=False
表示该字段不能为空。
易错点:
- 模型类必须继承
Base
。 - 主键字段必须指定,否则表无法正常创建。
- 字段类型要和数据库类型对应,长度限制要合理。
4. 创建表(生成数据库表结构)
Base.metadata.create_all(engine)
说明:
- 这行代码会根据所有继承了
Base
的模型类,在数据库中创建对应的表。 - 如果表已存在,不会重复创建。
5. 增删改查操作示例
说明: 历史背景(删除,查询等方法类似,增加操作不变)
在 SQLAlchemy 1.x 时代,ORM 查询主要使用 session.query():
user = session.query(User).filter(User.name == "Alice").first()
从 SQLAlchemy 1.4 开始,引入了新的 2.0 风格查询 API,推荐使用 select() 构建查询语句:
from sqlalchemy import select
stmt = select(User).where(User.name == "Alice") user = session.execute(stmt).scalars().first()
SQLAlchemy 1.4 提供了 两种风格同时兼容,但到了 2.0 正式版,session.query() 已被官方标记为 deprecated(弃用),未来版本可能会被完全移除。
以下操作均以新方法展示:
5.1 创建(插入)数据
with SessionLocal() as session:new_user = User(name='Alice', age=30)session.add(new_user)session.commit()
说明:
- 使用
with
可以自动关闭会话,避免资源泄漏。
易错点:
- 忘记 commit,数据不会保存。
5.2 查询数据
from sqlalchemy import selectwith SessionLocal() as session:stmt = select(User).where(User.name == 'Alice')user = session.execute(stmt).scalars().first()print(user)
易错点:
忘记
.scalars()
,会得到 Row 对象而不是 User 实例。未判断返回值是否为
None
,可能导致后续.id
等访问报错。
5.3 更新数据
with SessionLocal() as session:user = session.execute(select(User).where(User.name == 'Alice')).scalars().first()if user:user.age = 31session.commit()
5.4 删除数据
with SessionLocal() as session:user = session.execute(select(User).where(User.name == 'Alice')).scalars().first()if user:session.delete(user)session.commit()
易错点:
直接执行
delete(User)
不加where()
会删除整张表。删除后忘记
commit()
,操作不会生效。
6. 总结与易错事项提醒
操作环节 | 易错点与注意事项 |
---|---|
数据库连接 | 连接字符串格式错误(sqlite:/// vs postgresql:// );忘记设置 echo=True 调试;生产环境应使用连接池配置。 |
模型定义 | 忘记继承 Base ;未定义 __tablename__ ;未设置主键导致 ORM 无法管理;字段类型和数据库不匹配。 |
创建表 | 忘记执行 Base.metadata.create_all(engine) ;开发阶段修改模型后需手动迁移(建议用 Alembic 管理迁移)。 |
会话管理 | 忘记 commit() 导致数据不保存;未 close() 或未用 with Session() as session: 导致连接泄漏;推荐用 sessionmaker() 生成独立会话。 |
查询操作 | 常见错用:继续用 session.query() (已弃用);忘记 .scalars() 提取 ORM 对象导致拿到 Row;未检查结果为空返回 None 。 |
更新操作 | 直接修改对象但忘记 commit() ;update() 语句未加 .execution_options(synchronize_session="fetch") 导致会话状态不同步;更新条件写错导致批量修改全表数据。 |
删除操作 | delete() 条件写空导致全表删除;删除后忘记 commit() ;会话中已有该对象时未同步导致后续查询异常。 |
异常处理 | 未捕获 IntegrityError (主键/唯一约束冲突);出现异常后忘记 session.rollback() 导致会话进入无效状态。 |