Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unable to use flask.g to access variables in other functions

Tags:

python

flask

I'm trying to use flask.g to store variables that can be accessed in other functions, but I don't seem to be doing something correctly. The application generates the following error when I try to access g.name: AttributeError: '_RequestGlobals' object has no attribute 'name'.

The documentation for flask.g says:

Just store on this whatever you want. For example a database connection or the user that is currently logged in.

Here's a complete, minimal example that illustrates the error that I receive when trying to access the variable outside of the function it was created in. Any help would be greatly appreciated.

#!/usr/bin/env python

from flask import Flask, render_template_string, request, redirect, url_for, g
from wtforms import Form, TextField

application = app = Flask('wsgi')

@app.route('/', methods=['GET', 'POST'])
def index():
    form = LoginForm(request.form)

    if request.method == 'POST' and form.validate():
        name =  form.name.data
        g.name = name

        # Need to create an instance of a class and access that in another route
        #g.api = CustomApi(name)

        return redirect(url_for('get_posts'))

    else:

        return render_template_string(template_form, form=form)

@app.route('/posts', methods=['GET'])
def get_posts():
    # Need to access the instance of CustomApi here
    #api = g.api
    name = g.name
    return render_template_string(name_template, name=name)


class LoginForm(Form):
    name = TextField('Name')

template_form = """
{% block content %}
<h1>Enter your name</h1>

<form method="POST" action="/">
    <div>{{ form.name.label }} {{ form.name() }}</div><br>
    <button type="submit" class="btn">Submit</button>    
</form>
{% endblock %}

"""

name_template = """
{% block content %}

    <div>"Hello {{ name }}"</div><br>

{% endblock %}

"""

if __name__ == '__main__':
    app.run(debug=True)
like image 319
Raj Avatar asked Dec 07 '12 05:12

Raj


3 Answers

If you need to track authentication information, I'd suggest one of the Flask plugins like Flask-Login or Flask-Principal.

For example, we use Flask-Principal. It raises the identity-loaded signal when somebody authenticates (or it detects an authentication cookie). We then map their logged-in identity with a user in our database. Something like this:

# not actual code
@identity_loaded.connect_via(app)
def on_identity_loaded(sender, identity):
  user = Person.query.filter(Person.username==identity.person.username).one()
  g.user = user

and then we can use g.user in any controller or template. (We're actually ripping a lot of this out, it was a easy, lazy hack that's caused more trouble than it's worth.)

If you don't want to use a module, there's a built-in signal you can hook into at the start of every request:

http://flask.pocoo.org/docs/tutorial/dbcon/

# This runs before every request
@app.before_request
def before_request():
    g.user = your_magic_user_function()

and g.user would then be magically available everywhere.

I hope that helps!

like image 133
Rachel Sanders Avatar answered Nov 04 '22 22:11

Rachel Sanders


The g object is a request-based object and does not persist between requests, i.e. g is recreated between your request to index and your request to get_posts.

Application Globals in Flask:

Flask provides you with a special object that ensures it is only valid for the active request and that will return different values for each request. In a nutshell: it does the right thing, like it does for request and session.

For persistent storage of tiny data between requests use sessions instead. You may (but should not) get away with storing the data in the app object directly for global (all sessions) application state, similar to what config does, if you find a really good reason to do so.

For more complex data use databases.

like image 41
soulseekah Avatar answered Nov 04 '22 22:11

soulseekah


Just use sessions in flask. In your case, you just want to save the user/name in your request and the easiest way is to use sessions.

from flask import session
app.secret_key = 'some key for session'

Then, your functions could be changed as below:

@app.route('/', methods=['GET', 'POST'])
def index():
    form = LoginForm(request.form)
    if request.method == 'POST' and form.validate():
        session['name'] =  form.name.data
        return redirect(url_for('get_posts'))
    else:
        return render_template_string(template_form, form=form)

@app.route('/posts', methods=['GET'])
def get_posts():
    if 'name' in session:
        name = session['name']
    else:
        name = "Unknown"
    return render_template_string(name_template, name=name)
like image 1
codegeek Avatar answered Nov 04 '22 23:11

codegeek