在请求上下文外部(在生成器内部)设置flask会话变量

时间:2018-07-04 09:50:58

标签: python flask generator flask-session

我有一个烧瓶视图,该烧瓶视图被执行以将一些信息加载到生成器中(我正在使用生成器,以便可以连续产生进度-已加载多少信息)。这是视图的样子:

@app.route("/progress", methods=['GET'])
def progress():
     gen = get_user_saved_tracks(session['token'], session['spotify_id'], session)
     return Response(gen, mimetype= 'text/event-stream')

def get_user_saved_tracks(token, id, session):
    #load information and keep yielding
    session['info'] = info

我想将加载到会话变量中的信息存储在生成器内部(此生成器函数在请求上下文之外的其他文件中定义)。但是,当我尝试访问会话变量时,出现以下错误:

  

RuntimeError:在请求上下文之外工作。

那么,有没有办法以这种方式将信息写入会话?我现在正在使用FileSystemSessionInterface,但愿意使用redis会话,如果可以解决我的问题。

更新:

按照Sraw的建议,我尝试了以下更改:

from flask import current_app
app = current_app._get_current_object()
def get_user_saved_tracks(token, id,session):
    with app.app_context():
        session['info'] = info

但是我仍然遇到相同的错误。

更新2:

因此,我需要使用实际的应用程序实例而不是使用current_app(应用程序对象是在其他文件中创建的-app.py)

from app import app
def get_user_saved_tracks(token, id,session):
    with app.app_context():
        session['info'] = info

执行此操作时,出现相同的错误:

  

RuntimeError:在请求上下文之外工作。

更新3:

以下是get_user_saved_tracks的代码:

def get_user_saved_tracks(token, id, session, j, service):
    tracks = []
    for i in range(100):
        a = service.current_user_saved_tracks(limit=50, offset=i*50)
        if len(a['items']) == 0:
            break
        yield "data:" + "lib" + str((float(i+1)/(j))*100) + "\n\n"
        time.sleep(0.5)
        tracks.extend(a)

    session['tracks'] = tracks
    session.modified = True
    yield "data:" + "close" + "\n\n"

2 个答案:

答案 0 :(得分:0)

在类似的设置中,我会收到与您相同的错误。但是使用:

return Response(stream_with_context(....),
                mimetype='text/event-stream')

已解决。因此,对于您而言,这意味着:

from flask import Flask, stream_with_context, request, Response, session
....

return Response(stream_with_context(get_user_saved_tracks(session['token'], session['spotify_id'], session),
                mimetype='text/event-stream')

编辑:

通过使用回调函数来完成您想要完成的工作的纯技术方法。如果这 你想用这种方式是一个不同的问题。 您引入了两个附加参数 j service (?)。

def get_user_saved_tracks(cb, token, id, j, service):
    #tracks = []
    for i in range(100):
        a = service.current_user_saved_tracks(limit=50, offset=i*50)
        if len(a['items']) == 0:
            break
        yield "data:" + "lib" + str((float(i+1)/(j))*100) + "\n\n"
        time.sleep(0.5)
        #tracks.extend(a)
        cb(a)  # <<--------

    #self.session['tracks'] = tracks
    #self.session.modified = True
    yield "data:" + "close" + "\n\n"

@app.route("/progress", methods=['GET'])
def progress():
    # add a callback function to update the session for the 'a' you
    # calculate in get_user_saved_tracks(). The callback updates the session
    session['tracks'] = []
    def cb(l):
        session['tracks'].extend(l)
    session.modied = True

    return Response(stream_with_context(get_user_saved_tracks(cb, session['token'], session['spotify_id']),  # j and service ?
            mimetype='text/event-stream')

答案 1 :(得分:0)

我刚刚解决了我们的问题。调用此按钮可将会话保存到任何地方。

def _session_save():
    from flask.globals import _request_ctx_stack
    app.session_interface.save_session(app, _request_ctx_stack.top.session, flask.Response())

我尚未正确检查它,所以最终的解决方案可能看起来像这样:

def _session_save(session):  # pass flask.session from context
    app.session_interface.save_session(app, session, flask.Response())