一、 为什么读这本书?
1.平时工作中用的都是 SQLAlchemy 1 的语法,因为 SQLAlchemy 2 发布已经有好长一段时间了,也是未来的趋势,所以想了解一下SQLAlchemy 2 的语法。
2.个人觉得 SQLAlchemy 的文档很混乱,经常找不到自己想要的内容,想了解一下其它人是怎么使用文档的。
基于以上两个目的,鉴于作者(Miguel Grinberg) 之前写过一本《Flask Web Development》(中译版是《Flask Web开发:基于Python的Web应用开发实战》),个人觉得还行,所以就选择该书作为了解 SQLAlchemy 2 语法的切入点。
二、这本书写了什么?
本书总共包含 8 个章节。
第 1 章:Database Setup
介绍如何在项目中使用常见的关系型数据库,如:SQLite, MySQL, PostgreSQL。
第 2 章:Database Tables
介绍数据库表的操作,以及常见的 CRUD 操作。个人觉得本章是本书写得最好的一章,也是最具有实战意义的一章。查询操作示例:
SQLAlchemy 1 版本的查询语句是:
<pre class="md-fences md-end-block ty-contain-cm modeLoaded" spellcheck="false" lang="" cid="n12" mdtype="fences" style="box-sizing: border-box; --tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; --tw-rotate: 0; --tw-skew-x: 0; --tw-skew-y: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-pan-x: ; --tw-pan-y: ; --tw-pinch-zoom: ; --tw-scroll-snap-strictness: proximity; --tw-ordinal: ; --tw-slashed-zero: ; --tw-numeric-figure: ; --tw-numeric-spacing: ; --tw-numeric-fraction: ; --tw-ring-inset: ; --tw-ring-offset-width: 0px; --tw-ring-offset-color: #fff; --tw-ring-color: rgb(59 130 246 / .5); --tw-ring-offset-shadow: 0 0 #0000; --tw-ring-shadow: 0 0 #0000; --tw-shadow: 0 0 #0000; --tw-shadow-colored: 0 0 #0000; --tw-blur: ; --tw-brightness: ; --tw-contrast: ; --tw-grayscale: ; --tw-hue-rotate: ; --tw-invert: ; --tw-saturate: ; --tw-sepia: ; --tw-drop-shadow: ; --tw-backdrop-blur: ; --tw-backdrop-brightness: ; --tw-backdrop-contrast: ; --tw-backdrop-grayscale: ; --tw-backdrop-hue-rotate: ; --tw-backdrop-invert: ; --tw-backdrop-opacity: ; --tw-backdrop-saturate: ; --tw-backdrop-sepia: ; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: pre; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;">from models import Product
products = Product.query.all()</pre>
SQLAlchemy 2 版本的查询语句是:
<pre class="md-fences md-end-block ty-contain-cm modeLoaded" spellcheck="false" lang="" cid="n14" mdtype="fences" style="box-sizing: border-box; --tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; --tw-rotate: 0; --tw-skew-x: 0; --tw-skew-y: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-pan-x: ; --tw-pan-y: ; --tw-pinch-zoom: ; --tw-scroll-snap-strictness: proximity; --tw-ordinal: ; --tw-slashed-zero: ; --tw-numeric-figure: ; --tw-numeric-spacing: ; --tw-numeric-fraction: ; --tw-ring-inset: ; --tw-ring-offset-width: 0px; --tw-ring-offset-color: #fff; --tw-ring-color: rgb(59 130 246 / .5); --tw-ring-offset-shadow: 0 0 #0000; --tw-ring-shadow: 0 0 #0000; --tw-shadow: 0 0 #0000; --tw-shadow-colored: 0 0 #0000; --tw-blur: ; --tw-brightness: ; --tw-contrast: ; --tw-grayscale: ; --tw-hue-rotate: ; --tw-invert: ; --tw-saturate: ; --tw-sepia: ; --tw-drop-shadow: ; --tw-backdrop-blur: ; --tw-backdrop-brightness: ; --tw-backdrop-contrast: ; --tw-backdrop-grayscale: ; --tw-backdrop-hue-rotate: ; --tw-backdrop-invert: ; --tw-backdrop-opacity: ; --tw-backdrop-saturate: ; --tw-backdrop-sepia: ; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: pre; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;">from sqlalchemy import select
from models import Product
query = select(Product)
result = session.execute(query)
products = result.scalars().all()</pre>
第 3 章: One-To-Many Relationships
介绍一对多关系,平时工作中用的最多。
第 4 章: Many-To-Many Relationships
介绍多对多关系,中规中矩。
第 5 章: Advanced Many-To-Many Relationships
介绍一些高级的多对多关系用法,平时工作中用的相对较少。
第 6 章: A Page Analytics Solution
本章写得不好,在实际项目中或者复杂的项目中很少这样使用。
第 7 章:Asynchronous SQLAlchemy
鉴于本人在实际工作中并未这样实用过,无法判断其用法是好的还是不好的,本章不评价。
第 8 章: SQLAlchemy and the Web
介绍在 Flask、FastAPI 中集成 SQLAlchemy,写得不好,在实际项目中或者复杂的项目中很少这样使用。
从 2025 年 6 月 21 日至 2025 年 7 月 2 日,期间断断续续花了 8 天阅读完《SQLAlchemy 2 In Practice》。
三、这本书特点
1.逻辑结构清晰,行文流畅
虽然这本书是作者自己出版的,但是作者是一个很负责的人,整本书逻辑结构清晰,总共 8 个章节,由易到难,逐渐递进。行文流畅,让读者阅读起来非常丝滑,基本讲明白了“为什么有这个东西,怎么用这个东西”。所以整本书 200 多页,我只花了 8 天就读完了。
2.内容简单
正因为第一个特点——“逻辑结构清晰,行文流畅”,所以其实我个人希望作者能多写一点,能更深入一点。这可能跟作者对本书的定位有关,可能作者想写的就是一本入门书。
3.缺乏工程性
以最后一章为例,如果后端使用 Flask, 那么最好是使用 flask-migrate, 不然数据库迁移就会变成非常麻烦。这也是作者所有的书给我的一种感觉,作者的很多写法没有错,但严格来说,充其量只能算作 demo,缺乏工程性,很难应用到大型项目中(或者说在大型项目中这样的代码还需要优化)。
四、这本书适合什么样的人?
在阅读本书的过程中,解决了我一直以来非常不理解的两个问题:
1.flask-sqlalchemy 文档开头的两行代码到底想表达什么?
<pre class="md-fences md-end-block ty-contain-cm modeLoaded" spellcheck="false" lang="" cid="n38" mdtype="fences" style="box-sizing: border-box; --tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; --tw-rotate: 0; --tw-skew-x: 0; --tw-skew-y: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-pan-x: ; --tw-pan-y: ; --tw-pinch-zoom: ; --tw-scroll-snap-strictness: proximity; --tw-ordinal: ; --tw-slashed-zero: ; --tw-numeric-figure: ; --tw-numeric-spacing: ; --tw-numeric-fraction: ; --tw-ring-inset: ; --tw-ring-offset-width: 0px; --tw-ring-offset-color: #fff; --tw-ring-color: rgb(59 130 246 / .5); --tw-ring-offset-shadow: 0 0 #0000; --tw-ring-shadow: 0 0 #0000; --tw-shadow: 0 0 #0000; --tw-shadow-colored: 0 0 #0000; --tw-blur: ; --tw-brightness: ; --tw-contrast: ; --tw-grayscale: ; --tw-hue-rotate: ; --tw-invert: ; --tw-saturate: ; --tw-sepia: ; --tw-drop-shadow: ; --tw-backdrop-blur: ; --tw-backdrop-brightness: ; --tw-backdrop-contrast: ; --tw-backdrop-grayscale: ; --tw-backdrop-hue-rotate: ; --tw-backdrop-invert: ; --tw-backdrop-opacity: ; --tw-backdrop-saturate: ; --tw-backdrop-sepia: ; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: pre; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;">class Base(DeclarativeBase):
pass</pre>
因为之前在 Flask 项目中直接使用的是 Flask-SQLAlchemy, 一直没看到这两行代码的应用,导致我一直不理解这两行的代码想表达什么。看完这本书我懂了,其实 Base 就是 Model,在 SQLAlchemy 中 model 必须显示继承 DeclarativeBase,至于 Flask-SQLAlchemy 为什么要在开头加这两句,不得而知,个人觉得没有必要。不过这已经不重要了,已经知道 sqlalchemy 的规则就可以了。
2.既然已经提供了 ForeignKey, 为什么还要使用 relationship() 呢?
ForeignKey 作用于数据库层面, relationship() 作用于 ORM 层面。
回到“为什么读这本书?”,对于“想了解一下SQLAlchemy 2 的语法”——本书已经解决了我的问题;对于“想了解一下其它人是怎么使用文档的”——个人还是觉得 SQLAlchemy 文档的返回和排版做得不好,阅读的时候,应该牢牢抓住“Content”这个页面(https://docs.sqlalchemy.org/en/20/contents.html)。
总体而言,本书写得还行,相对简洁,属于入门级教材,适合想对 SQLAlchemy 语法有所了解的初学者。
五、推荐指数
按照 5 星的标准,本书推荐指数 3 颗星。
六、参考资料
1. 编程
(1)豆瓣,Miguel Grinberg,《SQLAlchemy 2 In Practice》:https://book.douban.com/subject/36482906/
(2)源码,Github:https://github.com/miguelgrinberg/retrofun
2. 英语
(1) Etymology Dictionary:https://www.etymonline.com
(2) Cambridge Dictionary:https://dictionary.cambridge.org
欢迎搜索及关注:编程人(a_codists)