How to use g.user global in flask
Question:
As I understand the g variable in Flask, it should provide me with a global place to stash data like holding the current user after login. Is this correct?
I would like my navigation to display my user’s name, once logged in, across the site.
My views contain
from Flask import g #among other things
During login, I assign
user = User.query.filter_by(username = form.username.data).first()
if validate(user):
session['logged_in'] = True
g.user = user
It doesn’t seem I can access g.user. Instead, when my base.html template has the following…
<ul class="nav">
{% if session['logged_in'] %}
<li class="inactive">logged in as {{ g.user.username }}</li>
{% endif %}
</ul>
I get the error:
jinja2.exceptions.UndefinedError
UndefinedError: 'flask.ctx._RequestGlobals object' has no attribute 'user'
The login otherwise works fine. What am I missing?
Answers:
g
is a thread local and is per-request (See A Note On Proxies). The session
is also a thread local, but in the default context is persisted to a MAC-signed cookie and sent to the client.
The problem that you are running into is that session
is rebuilt on each request (since it is sent to the client and the client sends it back to us), while data set on g
is only available for the lifetime of this request.
The simplest thing to do (note simple != secure
– if you need secure take a look at Flask-Login) is to simply add the user’s ID to the session and load the user on each request:
@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
Minor correction, the g object is bound to the application context now instead of the request context.
I would try to get rid of globals all together, think of your applications as a set of functions that perform tasks, each function has inputs and outputs, and should not touch globals. Just fetch your user and pass it around, it makes your code much more testable. Better yet: get rid of flask, flask promotes using globals such as
from flask import request
As I understand the g variable in Flask, it should provide me with a global place to stash data like holding the current user after login. Is this correct?
I would like my navigation to display my user’s name, once logged in, across the site.
My views contain
from Flask import g #among other things
During login, I assign
user = User.query.filter_by(username = form.username.data).first()
if validate(user):
session['logged_in'] = True
g.user = user
It doesn’t seem I can access g.user. Instead, when my base.html template has the following…
<ul class="nav">
{% if session['logged_in'] %}
<li class="inactive">logged in as {{ g.user.username }}</li>
{% endif %}
</ul>
I get the error:
jinja2.exceptions.UndefinedError
UndefinedError: 'flask.ctx._RequestGlobals object' has no attribute 'user'
The login otherwise works fine. What am I missing?
g
is a thread local and is per-request (See A Note On Proxies). The session
is also a thread local, but in the default context is persisted to a MAC-signed cookie and sent to the client.
The problem that you are running into is that session
is rebuilt on each request (since it is sent to the client and the client sends it back to us), while data set on g
is only available for the lifetime of this request.
The simplest thing to do (note simple != secure
– if you need secure take a look at Flask-Login) is to simply add the user’s ID to the session and load the user on each request:
@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
Minor correction, the g object is bound to the application context now instead of the request context.
I would try to get rid of globals all together, think of your applications as a set of functions that perform tasks, each function has inputs and outputs, and should not touch globals. Just fetch your user and pass it around, it makes your code much more testable. Better yet: get rid of flask, flask promotes using globals such as
from flask import request