SQLAlchemy官方文档指南、整体架构思路
下面我会把你这个问题分成 4 大部分讲清楚:
- 你这段查询到底算 Core 还是 ORM
select()返回的对象到底是什么、常见有哪些方法- 怎么用 SQLAlchemy 官方文档快速定位你要的内容
- SQLAlchemy 2 的整体架构思路:几大模块分别解决什么问题
你这个问题问得非常好,因为一旦把这套“地图”建立起来,后面你就不会再陷入:
- “这个 API 到底在哪看?”
- “这个写法是 Core 还是 ORM?”
- “我现在应该查哪部分文档?”
这种混乱了。
一、你这段查询到底算 Core 还是 ORM?
你这段代码:
stmt = (
select(
User.id,
User.username,
Employee.name
)
.outerjoin(Employee, User.id == Employee.user_id)
)
result = await db.execute(stmt)
users = result.mappings().all()
1. 先说结论
这段写法更准确地说是:
ORM-enabled select 写法 或者叫: SQLAlchemy 2 统一查询风格下的 SQL Expression / ORM 混合风格
它不是“纯 ORM 实体查询”,但也不是传统意义上纯 Core 表级查询。
2. 为什么不是“纯 Core”
因为你这里用的是:
User.idUser.usernameEmployee.name
如果 User 和 Employee 是 ORM 映射类,那么这些列属性来自 ORM mapped class,不是 Table.c.column 这种纯 Core 表达。
纯 Core 更像这样:
stmt = select(users_table.c.id, users_table.c.username, employees_table.c.name)
这里的 users_table、employees_table 是 Table 对象。
3. 为什么又不算典型 ORM 对象查询
典型 ORM 查询通常是:
stmt = select(User)
result = await db.execute(stmt)
users = result.scalars().all()
这里返回的是 User 实 体对象。
而你这里:
select(User.id, User.username, Employee.name)
你查的是列,不是实体类本身。
所以结果不是 ORM 实体对象,而是行结果。你才会用:
result.mappings().all()
这说明你想拿的是:
[
{"id": 1, "username": "tom", "name": "Tom Employee"},
...
]
4. 所以它到底该怎么归类最准确
最准确的理解方式是:
这属于:
- SQLAlchemy 2 的统一
select()语法 - 使用的是 ORM 映射类属性
- 但结果是 列结果集,不是 ORM 实体对象
- 执行器是
Session/AsyncSession.execute(),因此属于 ORM 上下文中的 SQL 表达式查询
所以你可以这样记:
“你写的是 ORM 类列属性的 select 列查询,不是纯实体 ORM 查询,也不是纯 Table Core 查询。”
5. 一个最实用的判断标准
你可以用下面这套判断法:
A. 如果你 select(User) 或 select(User, Employee)
通常偏 ORM 实体查询
结果常配:
.scalars().all().unique()
B. 如果你 select(User.id, User.username, Employee.name)
通常偏列查询 / 行查询
结果常配:
.all().mappings().all().first()
C. 如果你 select(user_table.c.id, user_table.c.username)
通常偏纯 Core
二、你这段代码的结果为什么用 mappings() 很合理
你现在这段查询:
stmt = (
select(
User.id,
User.username,
Employee.name
)
.outerjoin(Employee, User.id == Employee.user_id)
)
result = await db.execute(stmt)
users = result.mappings().all()
如果你直接 .all(),结果通常像:
[(1, "tom", "Tom Employee"), (2, "jack", None)]
这当然也能用,但可读性不够好。
而 .mappings().all() 会更适合 API 层:
[
{"id": 1, "username": "tom", "name": "Tom Employee"},
{"id": 2, "username": "jack", "name": None},
]
这在 FastAPI 里非常常见。
三、select() 返回的对象到底是什么
select(...) 返回的是一个:
Select对象
它属于 SQLAlchemy 的 SQL Expression Language 体系。
你可以把它理解成:
一棵“尚未执行”的 SQL 语句构造对象
它不是结果,也不是连接,它只是“SQL 的抽象表示”。
1. Select 对象的本质
比如:
stmt = select(User.id, User.username)
此时 stmt 不是查询结果,而是一个“待编译 SQL”对象。
你可以:
- 继续加
where() - 加
join() - 加
order_by() - 加
limit() - 加
options() - 最后交给
Session.execute()/Connection.execute()
2. 你可以把 Select 理解成“可链式拼装 SQL 的 builder”
像这样:
stmt = (
select(User)
.where(User.is_active.is_(True))
.order_by(User.id.desc())
.limit(20)
)
每一步都在返回一个新的 SQL 表达式对象。
四、Select 对象常用方法到底有哪些
你说得对,Select 上方法很多,初学时很容易被吓到。
所以不要试图背全,要按用途分类记忆。
1. 最常用方法:按“作用类别”记
第一类:选择什么
select(...)
创建查询
add_columns()
追加列
stmt = select(User.id).add_columns(User.username)
with_only_columns()
替换列列表