我正在尝试使用flask.g
来存储可以在其他函数中访问的变量,但我似乎没有正确地执行某些操作。当我尝试访问g.name
时,应用程序会生成以下错误:AttributeError: '_RequestGlobals' object has no attribute 'name'
。
flask.g
的{{3}}说:
只要存储在你想要的任何东西上。例如数据库 连接或当前登录的用户。
这是一个完整的,最小的例子,它说明了我在尝试访问创建函数之外的变量时收到的错误。非常感谢任何帮助。
#!/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)
答案 0 :(得分:15)
g
对象是基于请求的对象,不会在请求之间保留,即在g
请求和index
请求之间重新创建get_posts
。
Flask为您提供了一个特殊对象,可确保仅对活动请求有效,并为每个请求返回不同的值。简而言之:它做的是正确的,就像它对请求和会话一样。
要在请求之间持续存储微小数据,请改用sessions
。您可以(但不应该)直接将数据存储在app
对象中以用于全局(所有会话)应用程序状态,类似于config
所做的,如果您找到了一个非常好的理由如此。
对于更复杂的数据使用数据库。
答案 1 :(得分:2)
如果您需要跟踪身份验证信息,我建议使用其中一个Flask插件,如Flask-Login或Flask-Principal。
例如,我们使用Flask-Principal。当某人进行身份验证时(或者它检测到身份验证cookie),它会引发加载身份的信号。然后,我们将他们的登录身份映射到我们数据库中的用户。像这样:
# 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
然后我们可以在任何控制器或模板中使用g.user。 (我们实际上正在扯掉很多这样的东西,这是一个简单,懒惰的黑客,它造成的麻烦超过了它的价值。)
如果您不想使用模块,可以在每个请求开始时挂入一个内置信号:
http://flask.pocoo.org/docs/tutorial/dbcon/
# This runs before every request
@app.before_request
def before_request():
g.user = your_magic_user_function()
然后g.user随处可见。
我希望有所帮助!
答案 2 :(得分:2)
只需在烧瓶中使用会话。在您的情况下,您只想在请求中保存用户/名称,最简单的方法是使用会话。
from flask import session
app.secret_key = 'some key for session'
然后,您的功能可以更改如下:
@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)
答案 3 :(得分:0)
我想进一步说明 g global 在存储数据中的使用。 g 仅存储带有请求的数据,当重定向到另一条路由时, g 全局设置回 null,即它重置为空。这意味着在一个请求中设置为 g 的任何内容都无法在另一个请求中访问。使用会话来存储将跨请求访问的数据。
使用 g global 的一个好处是在连接到数据库以获取用户时。例如,可能是数据库中的管理员。管理员可以使用以下方法存储在 g 全局中。
from flask import Flask, g
app = Flask(__name__)
@app.before_request
def text():
g.a = User.query.filter_by(email='admin@gmail.com')
@app.route("/getTrue", methods=['GET', 'POST'])
def getTrue():
form = UserForm()
if form.validate_on_submit():
if g.a == form.email.data:
return "Admin is logged in"
else:
return "User is logged in"
return render_template('login.html', form=form)
在上面的示例中,g 可用于保存将在另一个请求中使用的数据。我希望这会有所帮助。谢谢