"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类对象,并且对目标集合的参考很小。在低记忆条件下,GC可能会尝试收集Artist.query.get(id)结果,仅留下结果的tags集合(是AssociationProxy类对象),但是由于SQLalchemy的实现,需要具有关联代理的对象(懒惰加载机制),我相信)。

要解决这种情况,我们需要确保将Artist对象从Artist.query.get(id)调用返回的对象分配给一个变量,以使该对象的参考计数明确为非零值。因此:

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

它将按预期工作。简单,对吗?

相关内容

最新更新