我正在编写一个连接到数据库的应用程序.我想创建一次db连接,然后在应用程序的整个生命周期中重用该连接.

我还想验证用户的身份.用户的身份验证将仅在请求的有效期内有效.

我如何区分为flask应用程序的生命周期存储的对象与特定于请求的对象?我应该将它们存储在哪里,以便所有模块(以及后续的蓝图)都可以访问它们?

以下是我的示例应用程序:

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被擦干净了!我的数据库找不到了.

现在,我知道那个瓶子了.g used仅适用于该请求.但是现在它已经绑定到了应用程序(从0.10开始),我想知道如何将变量绑定到整个应用程序,而不仅仅是一个请求.

我错过了什么?

edit:我对MongoDB特别感兴趣——在我的例子中,维护到多个Mongo数据库的连接.我的最佳 Select 是在__init__.py中创建这些连接并重用这些对象吗?

推荐答案

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年内完成.

你的另一个问题是如何跟踪特定于登录用户的内容.在这种情况下,您确实需要存储一些与连接相关的数据.flask.g在任务结束时被清除,所以这不好.

你想用的是sessions.这是一个可以存储用户浏览器上cookie中存储的值(使用默认实现)的地方.由于cookie将与用户的浏览器向您的网站发出的每个请求一起传递,因此您将获得您在会话中输入的数据.

不过,请记住,会话并不存储在服务器上.它被转换成一个字符串,并来回传递给用户.因此,不能将DB连接之类的东西存储到它上.而是存储标识符(如用户ID).

确保用户身份验证有效是非常困难的.您需要确保的安全问题非常复杂.我强烈建议您使用Flask-Login之类的东西来处理这个问题.您仍然可以根据需要使用session来存储其他项目,也可以让Flask Login来确定用户ID,将所需的值存储在数据库中,并在每个请求中从数据库中检索它们.

总之,有几种不同的方法来做你想做的事情.每个都有自己的用途.

  • Globals适用于线程安全的项目(例如PyMongo的MongoClient).
  • flask.g可用于存储请求生命周期内的数据.对于基于SQLAlchemy的flask应用程序,通常要做的一件事是确保在使用after_request方法的请求结束时,所有更改同时发生.用flask.g来表示类似的内容非常有用.
  • Flask session可用于存储简单数据(字符串和数字,而不是连接对象),这些数据可用于来自同一用户的后续请求.这完全取决于使用cookie,因此用户可以随时删除cookie,并且"会话"中的所有内容都将丢失.因此,您可能希望将大部分数据存储在数据库中,会话用于识别与会话中的用户相关的数据.

Mongodb相关问答推荐

通过mongoDB中的查找从管道中删除被阻止的用户

Mongodb如果数组中有外部键,则将排序应用到查找结果

mongoose正在抛出Schema的错误has';t已在next.js中注册

MongoDb聚合查询问题

使用mongo'db.Decode(&dto)映射一个嵌套的 struct

.save() 不是函数 Mongoose

MongoDB 文档操作是原子的和隔离的,但它们是否一致?

Node.js 和 Passport 对象没有方法 validPassword

如何更新 mongodb 文档以向数组添加新元素?

在 Nodejs 中找不到模块

使用 nodejs/mongoose 部分更新子文档

如何在 mongodb 本机驱动程序中对 find() 进行字段 Select ?

MongoDB:在集合上设置 TTL 索引时出错: sessions

请按语法排序 Mongoid Scope

如何在 mongoDB 中聚合巨大的数组?

使用已排序的数据获取不同的值

如何使用 mgo 和 Go 查询 MongoDB 的日期范围?

mongo dbname --eval 'db.collection.find()' 不起作用

Lombok - java.lang.StackOverflowError:toString 方法上的 null

与 mongoose/node.js 共享数据库连接参数的最佳方式