如何用SQLAlchemy递归Selectinload加载自关联多对多层级数据
动态加载SQLAlchemy自关联多层级nodes的解决方案
问题背景
存在自关联多对多关系的数据结构如下:
{ "parent": { "child": { "nodes": [ { "nodes": [ { "attr": "value", "nodes": [] } ] }, { "nodes": [ { "attr": "value", "nodes": [] } ] } ] } } }
当前使用固定层级的selectinload查询只能获取3层级nodes数据,希望实现动态链式嵌套selectinload,自动加载多层级(比如50层)直到nodes为空数组,同时询问是否需要使用marshmallow-sqlalchemy。
核心解决方案:循环实现动态链式selectinload
不需要手动嵌套多层selectinload,可以通过循环动态构建嵌套的加载选项,代码示例如下:
from sqlalchemy.orm import selectinload # 初始化加载链:先加载Parent.child load_chain = selectinload(Parent.child) # 循环添加指定层数的nodes嵌套加载,这里以50层为例 for _ in range(50): load_chain = load_chain.selectinload(Node.nodes) # 假设nodes属性对应的模型是Node # 构建查询 statement = select(Parent)\ .filter(Parent.id == parent_id)\ .options(load_chain) result = await async_session.execute(statement) parent = result.scalars().first()
原理说明
selectinload返回的是Load对象,每次调用.selectinload()都会返回一个新的嵌套加载对象,通过循环可以不断链式叠加,最终生成包含50层nodes嵌套的加载选项,和手动写50层嵌套的效果完全一致。
是否需要marshmallow-sqlalchemy?
不需要。marshmallow-sqlalchemy主要用于数据序列化/反序列化(比如把SQLAlchemy模型转成JSON),而你当前的需求是在查询时自动加载多层级关联数据,这属于SQLAlchemy ORM的加载策略范畴,用上述动态构建selectinload的方案即可解决。
如果后续需要把加载后的模型转成符合结构的JSON,才需要用到marshmallow-sqlalchemy来定义序列化规则,但这和数据加载是两个独立的步骤。
内容的提问来源于stack exchange,提问作者Jon Hayden
相关产品推荐
相关产品推荐

