"stale association proxy, parent object has gone out of scope" 使用 Flask-SQLAlchemy
"stale association proxy, parent object has gone out of scope" with Flask-SQLAlchemy
我以前从来没有遇到过这个错误:
sqlalchemy.exc.InvalidRequestError: stale association proxy, parent object has gone out of scope
经过一些研究,看起来是因为在关联代理工作时父对象正在被垃圾回收。太棒了。
但是,我不确定它发生在哪里。
相关代码:
# models.py
class Artist(db.Model):
# ...
tags = association_proxy('_tags', 'tag',
creator=lambda t: ArtistTag(tag=t))
# ...
class Tag(db.Model):
# ...
artist = association_proxy('_artists', 'artist',
creator=lambda a: ArtistTag(artist=a))
# ...
class ArtistTag(db.Model):
# ...
artist_id = db.Column(db.Integer, ForeignKey('artists.id'))
artist = db.relationship('Artist', backref='_tags')
tag_id = db.Column(db.Integer, ForeignKey('tags.id'))
tag = db.relationship('Tag', backref='_artists')
# api/tag.py
from flask.ext.restful import Resource
from ..
class ListArtistTag(Resource):
def get(self, id):
# much safer in actual app
return TagSchema(many=True)
.dump(Artist.query.get(id).tags)
.data
我知道这是一个老问题,但我还没有在网络上的任何地方找到类似问题的明确解决方案,所以我决定在这里回复。
这里的关键是在对它们执行任何进一步的操作之前,将保存关联代理的对象分配给一个变量。关联代理不是常规对象属性,它会强制 GC 保留对父对象的引用。实际上,调用形式为:
tags = association_proxy('_tags', 'tag', creator=lambda t: ArtistTag(tag=t))
将导致创建一个新的 AssociationProxy
class 对象,对目标集合的引用很弱。在内存不足的情况下,GC 可能会尝试收集 Artist.query.get(id)
结果,只留下结果的 tags
集合(作为 AssociationProxy
class 对象),但要求对象具有由于 SQLAlchemy 的实现(我相信正是延迟加载机制),存在一个关联代理。
要解决这种情况,我们需要确保从 Artist.query.get(id)
调用返回的 Artist
对象被分配给一个变量,以便该对象的引用计数明确为 non-zero 值。所以这个:
class ListArtistTag(Resource):
def get(self, id):
# much safer in actual app
return TagSchema(many=True)
.dump(Artist.query.get(id).tags)
.data
变成这样:
class ListArtistTag(Resource):
def get(self, id):
artist = Artist.query.get(id)
return TagSchema(many=True)
.dump(artist.tags)
.data
它会按预期工作。简单吧?
我以前从来没有遇到过这个错误:
sqlalchemy.exc.InvalidRequestError: stale association proxy, parent object has gone out of scope
经过一些研究,看起来是因为在关联代理工作时父对象正在被垃圾回收。太棒了。
但是,我不确定它发生在哪里。
相关代码:
# models.py
class Artist(db.Model):
# ...
tags = association_proxy('_tags', 'tag',
creator=lambda t: ArtistTag(tag=t))
# ...
class Tag(db.Model):
# ...
artist = association_proxy('_artists', 'artist',
creator=lambda a: ArtistTag(artist=a))
# ...
class ArtistTag(db.Model):
# ...
artist_id = db.Column(db.Integer, ForeignKey('artists.id'))
artist = db.relationship('Artist', backref='_tags')
tag_id = db.Column(db.Integer, ForeignKey('tags.id'))
tag = db.relationship('Tag', backref='_artists')
# api/tag.py
from flask.ext.restful import Resource
from ..
class ListArtistTag(Resource):
def get(self, id):
# much safer in actual app
return TagSchema(many=True)
.dump(Artist.query.get(id).tags)
.data
我知道这是一个老问题,但我还没有在网络上的任何地方找到类似问题的明确解决方案,所以我决定在这里回复。
这里的关键是在对它们执行任何进一步的操作之前,将保存关联代理的对象分配给一个变量。关联代理不是常规对象属性,它会强制 GC 保留对父对象的引用。实际上,调用形式为:
tags = association_proxy('_tags', 'tag', creator=lambda t: ArtistTag(tag=t))
将导致创建一个新的 AssociationProxy
class 对象,对目标集合的引用很弱。在内存不足的情况下,GC 可能会尝试收集 Artist.query.get(id)
结果,只留下结果的 tags
集合(作为 AssociationProxy
class 对象),但要求对象具有由于 SQLAlchemy 的实现(我相信正是延迟加载机制),存在一个关联代理。
要解决这种情况,我们需要确保从 Artist.query.get(id)
调用返回的 Artist
对象被分配给一个变量,以便该对象的引用计数明确为 non-zero 值。所以这个:
class ListArtistTag(Resource):
def get(self, id):
# much safer in actual app
return TagSchema(many=True)
.dump(Artist.query.get(id).tags)
.data
变成这样:
class ListArtistTag(Resource):
def get(self, id):
artist = Artist.query.get(id)
return TagSchema(many=True)
.dump(artist.tags)
.data
它会按预期工作。简单吧?