我正在编写一个连接数据库的应用程序。我想创建一次db连接,然后在应用程序的整个生命周期中重用该连接。
我也想验证用户身份。用户的身份验证仅适用于请求的生命周期。
如何区分在烧瓶应用程序生命周期中存储的对象与特定于请求的对象?我在哪里存储它们以便所有模块(以及随后的蓝图)都可以访问它们?
以下是我的示例应用:
from flask import Flask, g
app = Flask(__name__)
@app.before_first_request
def setup_database(*args, **kwargs):
print 'before first request', g.__dict__
g.database = 'DATABASE'
print 'after first request', g.__dict__
@app.route('/')
def index():
print 'request start', g.__dict__
g.current_user = 'USER'
print 'request end', g.__dict__
return 'hello'
if __name__ == '__main__':
app.run(debug=True, port=6001)
当我运行此(Flask 0.10.1)并导航到http://localhost:6001/
时,控制台中会显示以下内容:
$ python app.py
* Running on http://127.0.0.1:6001/
* Restarting with reloader
before first request {}
after first request {'database': 'DATABASE'}
request start {'database': 'DATABASE'}
request end {'current_user': 'USER', 'database': 'DATABASE'}
127.0.0.1 - - [30/Sep/2013 11:36:40] "GET / HTTP/1.1" 200 -
request start {}
request end {'current_user': 'USER'}
127.0.0.1 - - [30/Sep/2013 11:36:41] "GET / HTTP/1.1" 200 -
也就是说,第一个请求按预期工作:flask.g
正在保存我的数据库,当请求启动时,它也有我的用户信息。
但是,根据我的第二次要求,要将flask.g擦干净!我的数据库无处可寻。
现在,我知道flask.g 使用仅应用于请求。但是现在它被绑定到应用程序(从0.10开始),我想知道如何将变量绑定到整个应用程序,而不仅仅是单个请求。
我错过了什么?
编辑:我对MongoDB特别感兴趣 - 就我而言,保持与多个Mongo数据库的连接。我最好的选择是在__init__.py
中创建这些连接并重用这些对象吗?
答案 0 :(得分:30)
flask.g
只会在请求期间存储内容。文档提到值存储在应用程序上下文而不是请求中,但这更多是一个实现问题:它不会改变flask.g
中的对象仅在同一个线程中可用的事实,并且在单个请求的生命周期内。
例如,在official tutorial section on database connections中,连接在请求开始时进行一次,然后在请求结束时终止。
当然,如果您真的想要,可以创建一次数据库连接,将其存储在__init__.py
中,并根据需要引用它(作为全局变量)。但是,您不应该这样做:连接可能会关闭或超时,并且您无法在多个线程中使用该连接。
由于您未指定如何在Python中使用Mongo,我假设您将使用PyMongo,因为它会为您处理所有connection pooling。
在这种情况下,你会做这样的事情......
from flask import Flask
from pymongo import MongoClient
# This line of code does NOT create a connection
client = MongoClient()
app = Flask()
# This can be in __init__.py, or some other file that has imported the "client" attribute
@app.route('/'):
def index():
posts = client.database.posts.find()
如果你愿意,你可以做这样的事情......
from flask import Flask, g
from pymongo import MongoClient
# This line of code does NOT create a connection
client = MongoClient()
app = Flask()
@app.before_request
def before_request():
g.db = client.database
@app.route('/'):
def index():
posts = g.db.posts.find()
这实际上并没有那么不同,但是对于您希望在每个请求上执行的逻辑(例如根据登录的用户将g.db
设置为特定数据库)可能会有所帮助。
最后,您可以意识到,使用Flask设置PyMongo的大部分工作可能都是在Flask-PyMongo为您完成的。
您的另一个问题涉及如何跟踪特定于登录用户的内容。在这种情况下,您需要存储一些与连接相关的数据。 <{1}}在reuquest结束时被清除,所以这没有用。
您要使用的是sessions。在这个位置,您可以存储存储在用户浏览器上的cookie中的值(使用默认实现)。由于cookie将随用户浏览器向您的网站发出的每个请求一起传递,您将获得您在会话中输入的数据。
但请记住,会话未存储在服务器上。它被转换为一个来回传递给用户的字符串。因此,您无法将数据库连接等内容存储到其中。您将改为存储标识符(如用户ID)。
确保用户身份验证的工作非常困难。您需要确保的安全问题非常复杂。我强烈建议使用像Flask-Login之类的东西来处理这个问题。您仍然可以根据需要使用flask.g
来存储其他项目,或者您可以让Flask-Login句柄确定用户ID并将所需的值存储在数据库中,并在每个请求中从数据库中检索它们。
因此,总而言之,有几种不同的方法可以做你想做的事情。每个人都有自己的用法。
session
可用于在请求的生命周期中存储数据。使用基于SQLAlchemy的烧瓶应用程序,常见的做法是确保在使用flask.g
方法的请求结束时立即发生所有更改。使用after_request
来做这样的事情非常有帮助。flask.g
可用于存储可用于来自同一用户的后续请求的简单数据(字符串和数字,而不是连接对象)。这完全取决于使用cookie,因此用户可以随时删除cookie,“会话”中的所有内容都将丢失。因此,您可能希望将大部分数据存储在数据库中,其中会话用于标识与会话中用户相关的数据。答案 1 :(得分:4)
“绑定到应用程序”并不意味着您认为它意味着什么。这意味着g
绑定到当前正在运行的请求。 Quoth the docs:
Flask为您提供了一个特殊对象,确保它只对活动请求有效,并为每个请求返回不同的值。
应该注意Flask's tutorials specifically do not persist database objects,但这不是normative for any application of substantial size。如果你真的有兴趣潜入兔子洞,我建议使用数据库连接池工具。 (例如this one,在上面的SO回答中提到)
答案 2 :(得分:1)
我建议您使用会话来管理用户信息。会话可以帮助您保存信息b / w多个请求,而烧瓶会为您提供会话框架。
from flask import session
session['usename'] = 'xyz'
查看扩展程序Flask-Login。它设计精良,可以处理用户身份验证。
对于数据库,我建议查看Flask-SQLAlchemy扩展名。这可以为您提供开箱即用的初始化,汇集,拆卸等功能。您需要做的就是在配置中定义数据库URI并将其绑定到应用程序。
from flask.ext.sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:////tmp/test.db'
db = SQLAlchemy(app)