使用Flask-SQLAlchemy“陈旧关联代理,父对象已超出范围”

时间:2015-05-05 04:04:51

标签: python flask sqlalchemy flask-sqlalchemy

我之前从未遇到过这个错误:

<li ng-repeat="employment in Employments"> {{employment.user.name}} </li>

在做了一些研究后,它看起来像是因为父对象在关联代理工作时被垃圾收集。奇妙。

但是,我不确定 在哪里发生。

相关代码:

sqlalchemy.exc.InvalidRequestError: stale association proxy, parent object has gone out of scope

1 个答案:

答案 0 :(得分:10)

我知道这是一个老问题,但我还没有在网络上的任何地方找到类似问题的明确解决方案,所以我决定在这里回复。

这里的关键是在对变量执行任何进一步操作之前将包含关联代理的对象分配给变量。关联代理不是常规对象属性,它会强制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

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