63

据我了解 Flask 中的 g 变量,它应该为我提供一个全局位置来存储数据,例如在登录后保存当前用户。这个对吗?

我希望我的导航在整个站点上显示我的用户名,一旦登录。

我的观点包含

from Flask import g #among other things

在登录期间,我分配

user = User.query.filter_by(username = form.username.data).first()
if validate(user):
    session['logged_in'] = True
    g.user = user

我似乎无法访问 g.user。相反,当我的 base.html 模板具有以下内容时...

<ul class="nav">
    {% if session['logged_in'] %}
        <li class="inactive">logged in as {{ g.user.username }}</li>
    {% endif %}
</ul>

我得到错误:

jinja2.exceptions.UndefinedError
UndefinedError: 'flask.ctx._RequestGlobals object' has no attribute 'user'

否则登录工作正常。我错过了什么?

4

3 回答 3

82

g是一个线程本地并且是每个请求的(请参阅代理注意事项)。这session也是一个本地线程,但在默认上下文中被持久化为MAC 签名的 cookie 并发送到客户端。

您遇到的问题session是在每个请求上都重新构建(因为它被发送到客户端并且客户端将其发送回给我们),而数据集g仅在请求的生命周期内可用。

简单的事情(注意simple != secure- 如果您需要安全,请查看Flask-Login)是简单地将用户的 ID 添加到会话并在每个请求上加载用户:

@app.before_request
def load_user():
    if session["user_id"]:
        user = User.query.filter_by(username=session["user_id"]).first()
    else:
        user = {"name": "Guest"}  # Make it better, use an anonymous User instead

    g.user = user
于 2012-11-29T17:40:32.843 回答
13

小修正,g 对象现在绑定到应用程序上下文而不是请求上下文。

“从 Flask 0.10 开始,它存储在应用程序上下文中,不再存储在请求上下文中,这意味着如果仅绑定了应用程序上下文而不是请求,它就变得可用。”

于 2015-10-08T03:20:39.760 回答
-29

我会尝试一起摆脱全局变量,将您的应用程序视为一组执行任务的函数,每个函数都有输入和输出,并且不应该接触全局变量。只需获取您的用户并传递它,它就会使您的代码更具可测试性。更好的是:摆脱烧瓶,烧瓶促进使用全局变量,例如

from flask import request
于 2016-02-10T15:11:41.660 回答