【问题标题】:Need access to flask request context & db session after they exit退出后需要访问烧瓶请求上下文和数据库会话
【发布时间】:2016-02-19 20:10:45
【问题描述】:

我正在编写一个烧瓶应用程序,将内容流式传输给用户,并且我正在尝试在这种流式传输发生时操纵数据库。这是一些示例代码(简化):

def work_hard(obj):
    yield 'About to do a lot of work...'
    obj.status = do_a_lot_of_work_very_slowly()
    yield obj.status
    db.session.commit()
    obj.more = more_slow_stuff()
    yield obj.more
    db.session.commit()
    yield 'Hard work is done!'

@app.route('/log/<int:objid>/work_hard', methods=['POST'])
def perform_action(objid):
    obj = MyModel.query.get(objid)
    return Response(work_hard(obj), mimetype='text/html')

这段代码给出了错误Instance &lt;MyModel at 0x7f5555f046a0&gt; is not bound to a Session; attribute refresh operation cannot proceed,但如果我在perform_action() 中调用db.session.commit() 而不是work_hard(),它可以工作。同样,如果我尝试访问flask 的request 实例,它在perform_action() 中有效,但在work_hard() 中无效(它抱怨我试图在请求上下文之外访问请求)。

我假设这些都是因为work_hard()perform_action() 返回之后执行。是否有可能以某种方式延长请求上下文以包含work_hard()?到目前为止,我只是将单个值从 request 传递到 work_hard() 并且工作到一定程度,但现在我需要提交到数据库,我不知道如何在这里修复数据库会话。

我不能只从perform_action() 调用db.session.commit(),我确实需要能够在数据库中实时进行多次更新,因为输出正在流式传输到 HTTP 客户端。

如果事实证明这是不可能的,我的备份计划是从子进程流式输出,然后在子进程中我将从那里连接到数据库,但我更愿意在同一个内完成所有操作尽可能处理。

谢谢!

【问题讨论】:

    标签: python-3.x flask sqlalchemy


    【解决方案1】:

    您可以使用stream_with_context() 在生成器运行时保留上下文(以及会话):

    return Response(stream_with_context(work_hard(obj)), ...)
    

    【讨论】:

    • 就是这样,谢谢!未来谷歌用户的快速说明:我的第一次尝试让我害怕sqlalchemy.exc.OperationalError: (sqlite3.OperationalError) no such savepoint: sa_savepoint_1 [SQL: 'RELEASE SAVEPOINT sa_savepoint_1'] 并在谷歌上搜索这提出了一些非常丑陋的解决方法,但这些解决方法适用于旧版本的 python。至少在 python 3.5 中,我所要做的就是停止调用db.session.begin_nested(),这是一个失败的实验,我无论如何都忘记删除了。它有效!
    【解决方案2】:

    使用application context 访问会话:with app.app_context

    def work_hard(obj):
        yield 'About to do a lot of work...'
        obj.status = "blub"
        yield obj.status
        with app.app_context():
            db.session.commit()
        obj.more = "fish"
        yield obj.more
        with app.app_context():
            db.session.commit()
        yield 'Hard work is done!'
    
    @app.route('/log/<int:objid>/work_hard', methods=['POST'])
    def perform_action(objid):
        def perform_action(objid):
        obj = MyModel.query.get(objid)
        return Response(work_hard(obj), mimetype='text/html')
    

    【讨论】:

      猜你喜欢
      • 2016-02-09
      • 2016-09-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-11-27
      • 2018-08-29
      • 2018-12-12
      • 1970-01-01
      相关资源
      最近更新 更多