当前位置:首页 > 技术 > 正文内容

SQLAlchemy ORM完全指南:Python数据库操作实战

访客 技术 2026年7月10日 1

概述

SQLAlchemy是Python生态系统中最强大的ORM(对象关系映射)库,它为开发者提供了高效、灵活的数据库操作方案。本文将系统性地介绍SQLAlchemy ORM的核心用法,帮助您快速掌握Python数据库开发技能。

目录

  1. 环境准备
  2. 核心概念
  3. 数据库连接
  4. 数据模型定义
  5. 表结构创建
  6. 基础数据操作
  7. 数据查询技巧
  8. 关联关系处理
  9. 事务控制
  10. 开发最佳实践

环境准备

首先需要安装SQLAlchemy核心包:

pip install sqlalchemy

根据实际使用的数据库类型,还需要安装对应的驱动包:

# PostgreSQL数据库
pip install psycopg2-binary

# MySQL数据库  
pip install mysql-connector-python

# SQLite为Python内置库,无需额外安装

核心概念

理解以下四个核心组件是掌握SQLAlchemy的关键:

  • Engine:数据库连接引擎,负责与数据库服务器通信
  • Session:数据库会话对象,管理所有数据的持久化操作
  • Model:数据模型类,映射到数据库中的表结构
  • Query:查询构建器,用于构造和执行各类数据库查询

数据库连接

使用create_engine函数建立数据库连接:

from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker

# 连接SQLite数据库
engine = create_engine('sqlite:///demo.db', echo=True)

# 连接PostgreSQL数据库
# engine = create_engine('postgresql://user:pass@localhost:5432/dbname')

# 连接MySQL数据库
# engine = create_engine('mysql+mysqlconnector://user:pass@localhost:3306/dbname')

# 初始化会话工厂
SessionFactory = sessionmaker(autocommit=False, autoflush=False, bind=engine)

# 创建会话实例
db_session = SessionFactory()

数据模型定义

使用declarative_base创建模型基类,并定义数据表结构:

from sqlalchemy import Column, Integer, String, ForeignKey
from sqlalchemy.orm import relationship, declarative_base

# 创建模型基类
Base = declarative_base()

class Author(Base):
    """作者表模型"""
    __tablename__ = 'authors'
    
    id = Column(Integer, primary_key=True, index=True)
    name = Column(String(50), nullable=False)
    email = Column(String(100), unique=True, index=True)
    
    # 一对多关系:作者有多篇文章
    articles = relationship("Article", back_populates="writer")

class Article(Base):
    """文章表模型"""
    __tablename__ = 'articles'
    
    id = Column(Integer, primary_key=True, index=True)
    title = Column(String(100), nullable=False)
    body = Column(String(1000))
    writer_id = Column(Integer, ForeignKey('authors.id'))
    
    # 多对一关系:文章属于一个作者
    writer = relationship("Author", back_populates="articles")
    
    # 多对多关系:文章有多个标签
    categories = relationship("Category", secondary="article_categories", back_populates="tagged_articles")

class Category(Base):
    """标签分类表模型"""
    __tablename__ = 'categories'
    
    id = Column(Integer, primary_key=True, index=True)
    name = Column(String(30), unique=True, nullable=False)
    
    tagged_articles = relationship("Article", secondary="article_categories", back_populates="categories")

# 多对多关联表
class ArticleCategory(Base):
    __tablename__ = 'article_categories'
    
    article_id = Column(Integer, ForeignKey('articles.id'), primary_key=True)
    category_id = Column(Integer, ForeignKey('categories.id'), primary_key=True)

表结构创建

根据模型定义创建数据库表:

# 创建所有定义的表
Base.metadata.create_all(bind=engine)

# 如果需要删除所有表
# Base.metadata.drop_all(bind=engine)

基础数据操作

插入数据

# 插入单条记录
new_author = Author(name="王小明", email="wangxm@example.com")
db_session.add(new_author)
db_session.commit()

# 批量插入多条记录
db_session.add_all([
    Author(name="李小红", email="lixh@example.com"),
    Author(name="赵小刚", email="zhaog@example.com")
])
db_session.commit()

查询数据

# 查询所有记录
all_authors = db_session.query(Author).all()

# 获取第一条记录
first_author = db_session.query(Author).first()

# 根据主键查询
author = db_session.query(Author).get(1)

更新数据

# 查询后更新
author = db_session.query(Author).get(1)
author.name = "王小明更新"
db_session.commit()

# 批量更新
db_session.query(Author).filter(Author.name.like("王%")).update(
    {"name": "王氏家族"}, 
    synchronize_session=False
)
db_session.commit()

删除数据

# 查询后删除
author = db_session.query(Author).get(1)
db_session.delete(author)
db_session.commit()

# 条件删除
db_session.query(Author).filter(Author.name == "李小红").delete(
    synchronize_session=False
)
db_session.commit()

数据查询技巧

基础查询

# 查询所有记录
authors = db_session.query(Author).all()

# 只查询特定字段
names = db_session.query(Author.name).all()

# 排序查询
authors = db_session.query(Author).order_by(Author.name.desc()).all()

# 限制返回数量
authors = db_session.query(Author).limit(10).all()

# 分页查询
authors = db_session.query(Author).offset(5).limit(10).all()

条件过滤

from sqlalchemy import or_, and_

# 精确匹配
author = db_session.query(Author).filter(Author.name == "王小明").first()

# 模糊匹配
authors = db_session.query(Author).filter(Author.name.like("王%")).all()

# IN查询
authors = db_session.query(Author).filter(
    Author.name.in_(["王小明", "李小红"])
).all()

# 多条件AND查询
authors = db_session.query(Author).filter(
    Author.name == "王小明",
    Author.email.like("%@example.com")
).all()

# OR查询
authors = db_session.query(Author).filter(
    or_(Author.name == "王小明", Author.name == "李小红")
).all()

# 不等于查询
authors = db_session.query(Author).filter(Author.name != "王小明").all()

聚合统计

from sqlalchemy import func

# 计数统计
total = db_session.query(Author).count()

# 分组统计
stats = db_session.query(
    Author.name,
    func.count(Article.id)
).join(Article).group_by(Author.name).all()

# 平均值
avg_id = db_session.query(func.avg(Author.id)).scalar()

# 求和
sum_id = db_session.query(func.sum(Author.id)).scalar()

关联查询

# 内连接查询
results = db_session.query(Author, Article).join(Article).filter(
    Article.title.like("%Python%")
).all()

# 左外连接
results = db_session.query(Author, Article).outerjoin(Article).all()

# 自定义连接条件
results = db_session.query(Author, Article).join(
    Article, Author.id == Article.writer_id
).all()

关联关系处理

# 创建带有关联的数据
author = Author(name="孙小七", email="sunxq@example.com")
article = Article(title="我的第一篇文章", body="内容", writer=author)
db_session.add(article)
db_session.commit()

# 通过关系属性访问关联数据
print(f"文章《{article.title}》的作者是:{article.writer.name}")
print(f"作者{author.name}的所有文章:")
for art in author.articles:
    print(f"  - {art.title}")

# 处理多对多关系
python_cat = Category(name="Python")
django_cat = Category(name="Django")

article.categories.append(python_cat)
article.categories.append(django_cat)
db_session.commit()

print(f"文章《{article.title}》的标签:")
for cat in article.categories:
    print(f"  - {cat.name}")

事务控制

# 手动事务控制
try:
    new_author = Author(name="测试作者", email="test@example.com")
    db_session.add(new_author)
    db_session.commit()
except Exception as error:
    db_session.rollback()
    print(f"事务失败: {error}")

# 使用上下文管理器的事务封装
from sqlalchemy.orm import Session

def create_author(db: Session, name: str, email: str):
    try:
        author = Author(name=name, email=email)
        db.add(author)
        db.commit()
        return author
    except Exception:
        db.rollback()
        raise

# 嵌套事务(保存点)
with db_session.begin_nested():
    author = Author(name="嵌套事务作者", email="nested@example.com")
    db_session.add(author)

# 手动保存点
savepoint = db_session.begin_nested()
try:
    author = Author(name="保存点作者", savepoint=db_session)
    db_session.add(author)
    savepoint.commit()
except:
    savepoint.rollback()

开发最佳实践

遵循以下最佳实践可以显著提升数据库操作的可靠性:

  1. 会话管理:每个请求创建独立会话,请求处理完毕后及时关闭
  2. 异常处理:始终捕获异常并执行回滚操作
  3. 查询优化:警惕N+1查询问题,使用预加载提升性能
  4. 连接池配置:合理设置连接池大小和超时参数
  5. 数据校验:在模型层或业务层进行数据完整性校验
# 会话管理的最佳实践
from contextlib import contextmanager

@contextmanager
def get_database():
    """数据库会话上下文管理器"""
    db = SessionFactory()
    try:
        yield db
        db.commit()
    except Exception:
        db.rollback()
        raise
    finally:
        db.close()

# 使用示例
with get_database() as db:
    author = Author(name="上下文作者", email="context@example.com")
    db.add(author)

总结

通过本文的系统学习,您应该能够:

  1. 完成SQLAlchemy的环境配置和数据库连接
  2. 设计并定义数据模型及表间关联
  3. 实现增删改查等基础数据库操作
  4. 构建多条件、多表连接的复杂查询
  5. 正确处理数据库事务和异常
  6. 遵循最佳实践构建健壮的数据库层

SQLAlchemy还提供了许多高级特性,如混合属性、事件监听器、自定义类型等,等待您在实际项目中进一步探索和应用。

标签: Python

相关文章

Linux crontab 详解

1) crontab 是什么cron 是 Linux 的定时任务守护进程;crontab 是用来编辑/查看“按时间周期执行命令”的表(cron table)。常见两类:用户 crontab:每个用户一份(crontab -e 编辑)系统级 crontab / cron.d:可指定执行用户(/etc/crontab、/etc/cron.d/*)2) crontab 时间...

富文本里可以允许的 HTML 属性

一、所有标签默认允许的安全属性(极少)class        (可选)id           (通常建议禁用)title️ 注意:id 容易被滥用做锚点注入,很多系统直接禁用class 允许的话最好只允许固定前缀(如 editor-*)二、a 标签允许属性<a href="" t...

Mac 安装 Node.js 指南

方法一:通过官网安装包(最简单,适合初学者)如果你只是想快速安装并开始使用,这是最直接的方法。访问 Node.js 官网。页面会显示两个版本:LTS (Recommended For Most Users):长期支持版,最稳定。建议选这个。Current:最新特性版,包含最新功能但可能不够稳定。下载 .pkg 安装包并运行。按照安装向导点击“下一步”即可完成。方法二:使用 Homebrew 安装(...

Dom\HTML_NO_DEFAULT_NS 的副作用:自动加闭合标签

在使用Dom\HTMLDocument时,Dom\HTML_NO_DEFAULT_NS 将禁止在解析过程中设置元素的命名空间, 此设置是为了与DOMDocument向后兼容而存在的。当使用它时,已知的一个副作用就是:自动加闭合标签例如 </img> 为什么会这样?当你使用:Dom\HTML_NO_DEFAULT_NS文档会变成 无命名空间模式,此时内部更接近 XML...

Laravel 事件和监听器创建

在 Laravel 中,使用 Artisan 命令创建 Events(事件) 和 Listeners(监听器) 是非常高效的。你可以通过以下几种方式来实现:1. 手动创建单个 Event如果你只想创建一个事件类,可以使用 make:event 命令:Bashphp artisan make:event UserRegistered执行后,文件将生成在 app/Even...

自定义域名解析神器 dnsmasq

什么是 dnsmasq?dnsmasq 是一个轻量级、功能强大的网络服务工具,专为小型和中等规模网络设计。它是一个综合的网络基础设施解决方案[1]。dnsmasq 能做什么?功能说明应用场景DNS 转发与缓存将 DNS 查询转发到上游服务器(ISP、Google DNS 等),并在本地缓存结果加快 DNS 查询速度,减少外部 DNS 流量本地 DNS解析本地网络设备的主机名,无需编辑&n...

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法和观点。