Flask:设置应用程序和请求特定的属性?

Posted

技术标签:

【中文标题】Flask:设置应用程序和请求特定的属性?【英文标题】:Flask: setting application and request-specific attributes? 【发布时间】:2013-10-06 13:21:52 【问题描述】:

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

我还想对用户进行身份验证。用户的身份验证将仅在请求的生命周期内有效。

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

这是我的示例应用:

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 中创建这些连接并重用这些对象吗?

【问题讨论】:

【参考方案1】:

“绑定到应用程序”并不意味着您认为它意味着什么。这意味着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】:

我建议你使用 session 来管理用户信息。会话可帮助您保存多个请求的黑白信息,Flask 已经为您提供了会话框架。

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)

【讨论】:

仅供参考,您无法在请求之外访问session【参考方案3】:

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 将与用户浏览器向您的网站发出的每个请求一起传递,因此您将可以使用您在会话中放入的数据。

但请记住,会话不会存储在服务器上。它变成一个字符串,来回传递给用户。因此,您不能将诸如数据库连接之类的内容存储在其上。您将改为存储标识符(如用户 ID)。

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

因此,总而言之,有几种不同的方法可以做您想做的事情。各有各的用途。

全局变量适用于线程安全的项目(例如 PyMongo 的 MongoClient)。 flask.g 可用于在请求的生命周期内存储数据。对于基于 SQLAlchemy 的烧瓶应用程序,一个常见的做法是确保所有更改同时发生,在请求结束时使用 after_request 方法。将flask.g 用于此类操作非常有帮助。 Flask session 可用于存储可用于来自同一用户的后续请求的简单数据(字符串和数字,而不是连接对象)。这完全取决于使用 cookie,因此用户在任何时候都可以删除 cookie,“会话”中的所有内容都将丢失。因此,您可能希望将大部分数据存储在数据库中,会话用于识别与会话中的用户相关的数据。

【讨论】:

关于flask.g:“从 Flask 0.10 开始,它存储在应用程序上下文中,不再存储在请求上下文中,这意味着如果仅绑定了应用程序上下文而不是请求,它就变得可用。 " - 烧瓶文档flask.pocoo.org/docs/0.12/api/#flask.g @Raymond 非常感谢您的评论。我对文档的差异和这个公认的答案感到非常困惑。

以上是关于Flask:设置应用程序和请求特定的属性?的主要内容,如果未能解决你的问题,请参考以下文章

使用 Postman 与请求发布到 Flask 填充不同的请求属性

flask_综合认证

Flask请求和应用上下文源码分析

Flask请求和应用上下文源码分析

python 框架Flask学习笔记之session

Flask的请求处理机制