Python Web应用开发之Flask框架——高级应用(一)

八、上下文管理

在 Flask 框架中,上下文管理是一项关键特性,它允许开发者在应用程序的不同部分之间共享数据,并且确保在请求处理期间相关的资源(如数据库连接)能够正确地初始化和清理。Flask 中有两种主要的上下文类型:应用上下文(app context)和请求上下文(request context)。

8.1 请求上下文

在 Flask 中,请求上下文是一个关键概念,它包含了处理请求所需的所有信息。当 Flask 接收到一个 HTTP 请求时,会创建一个请求上下文,这个上下文会一直存在,直到请求处理完成。请求上下文的存在使得在整个请求处理过程中,不同的函数和模块都能方便地访问与该请求相关的数据。它有两个核心对象request 对象、session 对象,前边已经介绍了request对象,这里重点介绍下session对象。

1.session对象

session对象是flask.sessions.Session类的实例,用于在不同请求之间存储特定于用户会话的数据。这对于维护用户状态,如用户登录状态、购物车内容等功能至关重要。

session 对象本质上是一个字典,Flask 使用加密的Cookie在客户端和服务器之间传递 session 数据。当客户端发起请求时,Flask 检查请求中的 session Cookie。如果 Cookie存在且签名验证通过,Flask 会将Cookie中的数据加载到 session 对象中,这样在视图函数中就可以访问和修改这些数据。当请求结束时,session 对象中的任何更改都会被序列化并存储回 session Cookie,发送给客户端。

在使用 session 之前,需要设置一个 SECRET_KEY。这个密钥用于对 session Cookie 进行加密和签名,确保数据的安全性。可以在 Flask 应用初始化时设置:

from flask import Flask, session

app = Flask(__name__)
app.secret_key = 'your_secret_key'

请务必将 'your_secret_key' 替换为一个强密钥。在生产环境中,建议从环境变量或配置文件中读取密钥,而不是硬编码。

from flask import Flask, session, request, redirect, url_for

app = Flask(__name__)
app.secret_key = 'your_secret_key'


@app.route('/login', methods=['GET', 'POST'])
def login():
    if request.method == 'POST':
        username = request.form.get('username')
        # 设置会话变量,将用户名存储在session中
        session['username'] = username
        return redirect(url_for('profile'))
    return '''
        
'''
@app.route('/profile') def profile(): # 从session中获取用户名 username = session.get('username') if username: return f'欢迎,{ username}!这是你的个人资料页面。' return redirect(url_for('login')) if __name__ == '__main__': app.run(debug=True)

2. 请求上下文的生命周期

  • 创建:当 Flask 应用接收到一个 HTTP 请求时,会自动创建请求上下文。请求上下文被压入一个栈(_request_ctx_stack)中,这个栈确保每个线程都有自己独立的上下文栈,保证多线程环境下请求处理的隔离性。

  • 使用:在请求处理过程中,例如在视图函数、中间件等地方,都可以通过requestsession对象访问请求上下文的信息。

  • 销毁:一旦请求处理完成,无论是正常结束还是发生异常,请求上下文都会从栈中弹出并销毁。这意味着requestsession对象中的数据在请求处理完成后将不再可用,除非将相关数据保存到其他地方(如数据库)。

    from flask import Flask, session, request, redirect, url_for
    
    app = Flask(__name__)
    app.secret_key = 'your_secret_key'
    
    
    # 创建
    @app.route('/login', methods=['GET', 'POST'])
    def login():
        if request.method == 'POST':
            username = request.form.get('username')
            session['username'] = username
            return redirect(url_for('profile'))
        return '''
            
    '''
    # 使用 @app.route('/profile') def profile(): username = session.get('username') if username: return f'欢迎,{ username}!这是你的个人资料页面。' return redirect(url_for('login')) # 销毁 @app.route('/logout') def logout(): # 从session中移除用户名 session.pop('username', None) return redirect(url_for('login')) if __name__ == '__main__': app.run(debug=True)

3. 手动操作请求上下文

​ 在某些情况下,例如单元测试或者需要模拟请求的场景中,可能需要手动操作请求上下文。可以使用with语句结合app.test_request_context()来手动创建请求上下文。例如:

from flask import Flask, request

app = Flask(__name__)


@app.route('/')
def index():
    return f"请求路径: {
     request.path}"


with app.test_request_context('/test_path'):
    result = index()
    print(result)
 
  • 在上述代码中,app.test_request_context('/test_path')创建了一个模拟的请求上下文,路径为/test_path。在这个上下文环境中调用index函数,就好像 Flask 真正接收到了一个指向/test_path的请求一样。

8.2 应用上下文

在 Flask 中,应用上下文(Application Context)是一个重要的概念,它管理着与 Flask 应用实例相关的数据和状态。与请求上下文主要处理单个请求不同,应用上下文的作用域更侧重于整个应用程序,并且在应用的生命周期内可能会被多次激活和使用。

1. 应用上下文的作用

  • 存储应用级数据:应用上下文提供了一个地方来存储与应用相关的全局数据,这些数据在整个应用的不同部分都可以访问。例如,可以在应用上下文中存储数据库连接池、配置对象等,这样在不同的视图函数、扩展或其他应用组件中都能方便地获取这些资源,而无需在每个地方重复创建或配置。
  • 关联应用实例:它将当前的执行环境与特定的 Flask 应用实例相关联。在多应用(如在一个进程中运行多个 Flask 应用实例)或者在使用 Flask 扩展的情况下,应用上下文确保每个操作都与正确的应用实例相关联,避免混淆和错误。

2. 应用上下文对象

​ Flask 的应用上下文主要由两个对象组成:

  • current_app:指向当前激活的 Flask 应用实例。通过这个对象,你可以访问应用的各种配置、属性和方法。例如,current_app.config 可以获取应用的配置信息,current_app.logger 可以使用应用的日志记录器。
  • g:这是一个全局对象,用于在请求处理过程中临时存储数据。与 current_app 不同,g 的数据只在当前请求处理期间有效,且每个请求都有自己独立的 g 对象。不过,由于应用上下文在请求处理期间也是激活的,所以可以在请求处理过程中通过 g 来传递一些与当前请求相关,但又可能在不同函数间共享的数据。

3. 应用上下文的激活与销毁

  • 自动激活:在处理请求时,Flask 会自动激活应用上下文和请求上下文。当一个请求进入应用,Flask 首先会激活应用上下文,然后再激活请求上下文。这确保了在请求处理过程中,应用级别的数据和当前请求相关的数据都可以被正确访问。
  • 手动激活:在某些情况下,比如在自定义的命令行脚本或者扩展中,可能需要手动激活应用上下文。可以使用 app.app_context() 方法来手动创建并激活应用上下文。例如:
from flask import Flask

app = Flask(__name__)

with app.app_context():
    # 在这个代码块内,应用上下文被激活
    print(current_app.config['SECRET_KEY'])

在上述代码中,with app.app_context() 语句创建了一个应用上下文,并在 with 代码块内保持激活状态。在这个代码块中,可以使用 current_app 访问应用的配置信息。

  • 销毁:当请求处理完成或者手动创建的应用上下文代码块结束时,应用上下文会被销毁。在销毁过程中,Flask 会自动清理与该应用上下文相关的资源,确保不会出现资源泄漏。

4. 应用上下文的使用场景

  • 数据库连接管理:在应用启动时,可以在应用上下文中初始化数据库连接池,并在整个应用的生命周期内复用这些连接。不同的视图函数在处理请求时,可以从应用上下文中获取数据库连接,而无需每次都重新建立连接,提高了应用的性能和资源利用率。例如:
import sqlite3
from flask import Flask, g

app = Flask(__name__)

def get_db():
    if 'db' not in g:
        g.db = sqlite3.connect('example.db')
    return g.db

@app.teardown_appcontext
def close_db(error):
    db = g.pop('db', None)
    if db is not None:
        db.close()

@app.route('/')
def index():
    db = get_db()
    # 使用数据库连接执行查询等操作
    return 'Hello, World!'

在上述代码中,get_db 函数在应用上下文中获取数据库连接,如果连接不存在则创建一个。@app.teardown_appcontext 装饰的 close_db 函数在应用上下文销毁时关闭数据库连接。此代码并不能直接运行,仅是一个示例,详细的数据库连接请看后面第九章数据库集成

  • 配置管理:应用上下文可以方便地访问应用的配置信息。例如,在视图函数或者扩展中,可以通过 current_app.config 获取配置参数,根据不同的配置执行不同的逻辑。
from flask import Flask, current_app

app = Flask(__name__)
app.config['DEBUG_MODE'] = True

@app.route('/')
def index():
    if current_app.config['DEBUG_MODE']:
        return '应用处于调试模式'
    return '应用处于生产模式'

理解和正确使用应用上下文对于构建健壮、高效的 Flask 应用至关重要,它提供了一种有效的方式来管理应用级别的资源和数据,并确保这些资源在整个应用生命周期内的正确使用和清理。

九、会话管理

在 Web 应用开发中,会话管理是一项关键功能,它允许 Web 应用在多个请求之间跟踪用户状态和数据。在 Flask 框架里,会话管理通过 session 对象实现,该对象基于客户端的 Cookie 机制,提供了一种安全且便捷的方式来存储和访问用户特定的数据。

9.1 启用会话

Flask 中的会话默认是基于客户端的 Cookie 实现的。在应用中不需要额外的启用步骤,但需要设置一个密钥来对会话数据进行加密签名,以确保数据的安全性。

from flask import Flask

app = Flask(__name__)
app.secret_key ='my_secret_key'  # 请使用更复杂和安全的密钥在实际应用中

9.2 存储和获取会话数据

可以像操作字典一样存储和获取会话数据。

@app.route('/set_session')
def set_session():
    session['username'] = 'John'
    session['logged_in'] = True
    return 'Session data set'

@app.route('/get_session')
def get_session():
    username = session.get('username')
    logged_in = session.get('logged_in', False)
    return f'Username: {
     username}, Logged In: {
     logged_in}'

9.3 删除会话数据

@app.route('/clear_session')
def clear_session():
    session.pop('username', None)
    session.pop('logged_in', None)
    return 'Session data cleared'

9.4 会话有效期

1. 默认会话有效期

在 Flask 中,默认情况下,会话基于客户端的Cookie实现。会话Cookie在用户关闭浏览器时会被删除,这意味着会话数据的有效期默认到浏览器关闭为止。这种会话类型被称为 “非持久会话”。

2. 设置持久会话

如果你希望会话在浏览器关闭后仍然有效,可以通过将会话标记为持久化来实现。在 Flask 中,可以在设置会话数据时,通过设置 session.permanent = True 来实现。

python
from flask import Flask, session, redirect, url_for

app = Flask(__name__)
app.secret_key ='my_secret_key'

你可能感兴趣的:(Python,python,前端,flask)