本文介绍如何在 sqlalchemy 中对多对一/一对多关系中的父表和子表同时按时间范围条件过滤,避免 n+1 查询问题,并精准控制 `selectinload` 加载的子对象集合。
在使用 SQLAlchemy 处理带有效期(start_date/end_date)的复合主键模型时,常遇到一个典型需求:既要筛选满足时间条件的父对象,又要确保其关联的子对象也满足独立的时间条件。例如,查询某个编号为 ‘1234’ 且在 2024-02-14 有效期内的 Parent,同时仅加载其自身也在该日期范围内有效的 Child 记录。
直接在 .filter() 中添加子表条件(如 Child.start_date > …)是无效的——SQLAlchemy 会忽略它,因为主查询未显式 JOIN 子表,且 filter() 作用于整个查询的 WHERE 子句,无法影响 selectinload 的加载逻辑。
✅ 正确解法是:将子对象的过滤条件嵌入到关系加载器(loader option)中,而非主查询的 filter()。SQLAlchemy 提供了 .and_() 方法,可为 selectinload、joinedload 等指定关联查询的附加 WHERE 条件。
以下为完整、可运行的示例(兼容 SQLAlchemy 1.4+ 和 2.0+ 风格):