文章内容
2024/12/17 1:42:16,作 者: 黄兵
sqlalchemy.exc.InvalidRequestError: 'model' does not support object population - eager loading cannot be applied.
最近在使用 SQLAlchemy 的时候,出现了这个错误:
sqlalchemy.exc.InvalidRequestError: 'model' does not support object population - eager loading cannot be applied.
具体模型代码:
class Category(db.Model):
__tablename__ = 'categories'
__table_args__ = {'comment': 'API 文档目录'}
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(64))
parent_id = db.Column(db.Integer, db.ForeignKey('document_categories.id'), nullable=True,
comment='父类别ID')
link_text = db.Column(db.String(128), index=True, unique=True, comment='文档类别链接')
rank = db.Column(db.SmallInteger, comment='类别排名')
type_id = db.Column(db.Integer, db.ForeignKey('document_category_types.id'))
is_top_menu = db.Column(db.Boolean, comment='是否为顶部菜单')
is_expandable_menu = db.Column(db.Boolean, comment='是否为可扩展菜单')
title = db.Column(db.String(64), comment='文档目录标题')
sub_title = db.Column(db.String(128), comment='文档目录副标题')
documents = db.relationship('Document', backref='category', lazy='dynamic')
introductions = db.relationship('DocumentCategoryIntroduction', backref='category', lazy='dynamic')
# 自引用关系:一个类别可以有多个子类别,且每个类别可以有一个父类别
parent = db.relationship('DocumentCategory', remote_side=[id],
backref=db.backref('subcategories', lazy='dynamic'))出现错误的代码:
get_menu = (DocumentCategory.query.filter_by(type_id=get_category_type.id).filter(
DocumentCategory.parent_id == None).order_by(DocumentCategory.rank).options(
joinedload(DocumentCategory.subcategories)).all())出现问题的原因:
在模型中
subcategories 被定义为 lazy='dynamic',这种情况下,SQLAlchemy 无法通过 joinedload 进行预加载操作。原因分析:
lazy='dynamic'
dynamic 懒加载模式返回一个查询对象,而不是实际的数据集合,因此无法用于 joinedload 进行预加载。joinedload的限制
joinedload 适用于 lazy='select' 或 lazy='joined' 类型的关系,而不适用于 lazy='dynamic'。解决方案:
将
lazy='dynamic' 改为 lazy='select 或 lazy='joined',这样可以支持 joinedload 进行预加载。# 修改 CloudDocumentCategory 模型
parent = db.relationship(
'DocumentCategory',
remote_side=[id],
backref=db.backref('subcategories', lazy='select') # 这里改成 'select' 或 'joined'
)
lazy='select':按需加载(默认行为)。lazy='joined':在查询父记录时,直接使用 JOIN 加载子记录。修改后,代码中可以正常使用
joinedload:get_menu = (
CloudDocumentCategory.query
.filter_by(type_id=get_category_type.id, parent_id=None)
.order_by(CloudDocumentCategory.rank)
.options(joinedload(CloudDocumentCategory.subcategories)) # 预加载子菜单
.all()
)
黄兵个人博客原创。
评论列表