您现在的位置是:首页 >其他 >使用Flask高效构建Web应用网站首页其他

使用Flask高效构建Web应用

楼下安同学 2024-09-16 00:01:02
简介使用Flask高效构建Web应用

在这里插入图片描述

1、聊聊Flask框架

Flask官方文档

  Flask是Armin ronacher基于Python开发的微型Web框架,诞生于2010年,它依赖于jinja2模板和Werkzeug WSGI服务。Flask的核心简单易于扩展,它不会替你做出太多决策比如使用何种数据库或模板引擎,这些都可以根据自己的需求进行选择和替换。Flask的设计理念是让发人员可以根据自己的需求进行自定义,同时提供足够的灵活性和可扩展性

2、Falsk常用第三方扩展包

可在Flask官方文档的扩展包页面中找到许多常用的Flask扩展包

插件功能
Flask-SQLAlchem使用SQLAlchemy ORM
Flask-Login处理用户认证和会话管理
Flask-Uploads处理文件上传
Flask-Admin构建管理界面
Flask-WTF处理Web表单
Flask-RESTful构建RESTful API
Flask-Mail发送电子邮件
Flask-Caching缓存数据
Flask-Jwt-Extended处理JSON Web Tokens
Flask-SocketIO处理WebSocket通信
Flask-Migrate处理数据库迁移
Flask-Assets处理静态资源
Flask-Cors实现跨域
Flask-Bcrypt实现加密

3、Flask钩子函数

钩子函数执行时间特别说明
before_first_request项目初始化时的钩子
before_request在每次请求前执行
after_reauest如果没有抛出错误,在每次请求后执行接收视图函数做出的响应
teardown_request在每次请求后执行接收错误信息,如果有相关错误抛出

4、Flask路由

路由和视图的名称必须全局统一,不能出现重复,否则报错

4.1 flask默认支持的转换器

名称描述
string默认类型,接受不带斜杠的任何文本
int接受正整数
float接受正浮点值
path接收string但也接受斜线
uuid接受UUID字符串

4.2 任意路由参数

# 不限定类型
@app.route('/user/<params>')
def user_info(params):
    return 'params %s' % params
  
# 限定数据类型  中间不能有空格
@app.route('/user/<int:uid>')
def user_info(uid):
    return 'uid %d' % uid

4.3 自定义路由转换器

from werkzeug.routing import BaseConverter

class MobileConverter(BaseConverter):
    """check mobile"""
    def __init__(self,map,*args):
        super().__init__(map)
        self.regex = "1[3-9]d{9}"

app.url_map.converters['mobile'] = MobileConverter

@app.route('/user/<mobile:mobile>', methods=['get', 'post'])
def test_view(mobile):
    return mobile

5、HTTP请求与响应

flask中使用request获取当前请求的对象

5.1 请求

获取常用的请求信息:

信息描述示例
request.method请求的HTTP方法GET, POST, PUT, DELETE等等
request.url请求的完整URLhttp://example.com/path?query=string
request.headers请求头部的字典形式{‘Content-Type’: ‘application/json’}
request.argsURL中的查询参数{‘key’: ‘value’}
request.form表单数据{‘username’: ‘john’, ‘password’: ‘123’}
request.files上传的文件{‘file’: }
request.cookies请求中的Cookie{‘session_id’: ‘abc123’}
request.remote_addr客户端的IP地址127.0.0.1
request.user_agent发起请求的UAMozilla/5.0 …
request.jsonJson格式的请求体数据{‘key’: ‘value’}
request.data请求体的原始数据(字节形式)b’raw data’

获取请求示例:

from flask import request, jsonify

from application.apps.index import index_blueprint

@index_blueprint.route("/index")
def index():
    data = request.get_json()
    
		# 数据处理...
    
    return jsonify(data='welcome flask!'), 200

5.2 响应

flask默认支持两种数据响应和页面响应

数据响应

from flask import make_response, jsonify

@app.route("/")
def index():
    # 默认响应html
    return '<h1>hello world!</h1>'
  	
    # 响应html
		return make_response('<h1>hello world!</h1>')
  
  	# 响应json
    return jsonify(msg='hello world!')		
页面响应
from flask import redirect

@app.route("/")
def handle_request():
  
  	# 重定向
    return redirect("http://www.example.com")
		
    # 视图方法内部跳转
    return redirect(url_for("view funcname"))
  
  	# 视图方法内部跳转携带参数
    return redirect(url_for("view funcname", params-name=''))

自定义http响应内容

from flask import make_response

@app.route("/")
def handle_request():
		response = Response('Custom Response')
    response.headers['Content-Type'] = 'text/plain'
    response.status_code = 200
    return response

6、异常捕获

6.1 主动抛出异常

可以使用abort方法抛出一个给定的状态码的HTTPException或者指定响应,一般用于权限校验等页面上错误展示

# 参数HTTP状态码
abort(500)

6.2 捕获自定义异常

初始化app的时候可以将捕获异常的方法注册,也可以使用装饰器

def exception_method_not_allow(error):
    logging.error("An exception occurred: {}".format(str(error)))
    return jsonify(msg='method not allowed'), 405

# 第一个参数可以是异常类型或者状态码
app.register_error_handler(405, exception_method_not_allow)

# 捕获自定义异常
@app.errorhandler(ZeroDivisionError)
def zero_division_error(e):
    return '除数不能为0'

7、context

  执行上下文:即语境,语意,在程序中可以理解为在代码执行到某一行时,根据之前代码所做的操作以及下文即将要执行的逻辑,可以决定在当前时刻下可以使用到的变量,或者可以完成的事情。Flask中上下文对象:相当于一个容器保存了程序运行过程中的变量、函数、类与对象等信息。Flask中有请求上下文和应用上下文。

  • 请求:发生http请求时,调用Flask.__call__()之后,在Flask对象内部创建的Request对象;
  • 应用:调用app = Flask(__name__)创建的这个对象app

7.1 请求上下文

  在flask中,可以直接在视图函数中使用request这个对象进行获取相关数据request就是请求上下文的对象,保存了当前本次请求的相关数据,请求上下文对象有:request、session。
  request封装了HTTP请求的内容,针对的是http请求。session用来记录用户会话中的信息。

7.2 应用上下文

  应用上下文,它不是一直存在的,只是request context 中操作当前falsk应用对象app的代理(local proxy)。它的作用主要是帮助 request 获取当前的flask应用相关的信息,它是伴request而生随request 而灭的。
  current_app是应用程序上下文,用于存储应用程序中的变量,可以通过current_app.name打印当前app的名称,也可以在current_app中存储一些变量,例如:

  • 应用的启动脚本是哪个文件,启动时指定了哪些参数
  • 加载了哪些配置文件,导入了哪些配置
  • 连接了哪个数据库
  • 有哪些可以调用的工具类、常量
  • 当前flask应用在哪个机器上,哪个IP上运行,内存多大
from flask import current_app

def index():
    print(current_app.config)   # 获取当前项目的所有配置信息
    print(current_app.url_map)  # 获取当前项目的所有路由信息

    return "<h1>hello world!</h1>"

7.3 g对象

  g对象是flask程序全局的一个临时变量,充当者中间媒介的作用,我们可以通过它传递一些数据,g对象保存的是当前请求的全局变量不同的请求会有不同的全局变量,通过不同的thread-id区别。

from flask import Flask, g

app = Flask(__name__)

@app.before_request
def before_request():
    g.name = "root"

@app.route(rule='/')
def index():
    print(g.name)  # 获取到全局变量root
    return "<h1>hello world!</h1>"


if __name__ == '__main__':
    app.run()

8、蓝图 Blueprint

  Blueprint是一个存储视图方法的容器,这些操作在这个Blueprint被注册到一个应用之后就可以被调用,Flask可以通过Blueprint来组织URL以及处理请求。Flask使用Blueprint让应用实现模块化,Blueorint具有如下属性:

  • 一个项目可以具有多个Blueprint
  • 可以将一个Blueprin注册到任何一个未使用的URL下比如"/“、”/api"或者子域名
  • 在一个应用中,一个模块可以注册多次
  • Blueorint可以单独具有自己的模板、静态文件或者其它的通用操作方法
  • 在一个应用初始化时,就应该要注册需要使用的Blueprint

8.1 蓝图使用

示例可以通过:http://127.0.0.1:5000/api/v1/index访问到蓝图中定义的视图函数

# 创建一个蓝图模块 
# __init__.py

from flask import Blueprint

index_blueprint = Blueprint("index_blueprint", __name__)

from application.apps.index.view import *


# views.py
from flask import jsonify

from application.apps.index import index_blueprint

@index_blueprint.route("/index")
def index():
    return jsonify(data='welcome flask!'), 200
  
# 注册蓝图到应用
app.register_blueprint(index_blueprint, url_prefix='/api/v1')

8.2 运行机制

  • 蓝图是保存了一组将来可以在应用app对象上执行的操作,注册路由就是一种操作
  • 当在app对象上调用route装饰器注册路由时,这个操作将修改对象的url_map路由表
  • 然而,蓝图对象根本没有路由表,当我们在蓝图对象上调用route装饰器注册路由时,它只是在内部的一个延迟操作记录列表defered_functions中添加了一个项
  • 当执行了app对象的register_blueprint()方法时,app应用对象将从蓝图对象的defered_functions列表中取出每一项,并以自身作为参数执行该匿名函数,即调用app应用对象的add_url_rule()方法,将蓝图的路由信息全部注册到应用对象app的url_map路由表

8.3 蓝图静态文件

  和app应用对象不同,蓝图对象创建时不会默认注册静态目录的路由。需要我们在创建时指定static_folder参数。下面的示例将蓝图所在目录下的static_home目录设置为静态目录。有了蓝图的静态目录以后,并不会影响原来项目中提供的static总静态文件目录的使用。

# index/__init__.py
from flask import Blueprint

index_blueprint = Blueprint("index_blueprint", __name__, static_folder="static_index")

9、实现异步

  如果在安装 Flask 时使用了额外的 async ( 即用 pip install flask[async] 命令安装),那么路由、出错处理器、请求前、请 求后和拆卸函数都可以是协程函数。这样,视图可以使用 async 定义,并使用 await

import logging
import asyncio

from flask import jsonify

from application.apps.index import index_blueprint
from application.extensions import redis_cli


@index_blueprint.route("/index")
async def index():
  	# 模拟耗时
    await asyncio.sleep(1)
    return jsonify(data='welcome flask!'), 200

9.1 性能

  异步函数需要一个事件循环来运行。 Flask作为WSGI应用,使用一个worker来处理一个请求响应周期。当请求进入异步视图时Flask会在一个线程中启动一个事件循环在其中运行视图函数然后返回结果。即使对于异步视图,每个请求仍然会绑定一个worker。好处是您可以在一个视图内运行异步代码,例如多个并发数据库查询,对外部API的HTTP请求,等等。但是,应用程序可以处理的请求并发数量将保持不变。

  异步本质上并不比同步快。 在执行并发IO绑定任务时, 异步是有益的。但是对于CPU密集型任务,则未必有用,因此传统的Flask视图仍然适用于大多数用例。 Flask异步支持的引入,带来本地化编写和使用异步代码的可能性。

10、搭建一个合理的项目架构

适合一个中型项目使用,区分模块,区分环境

在这里插入图片描述

11、 总结

  从 Flask 0.11 开始,Flask已经内置了一个命令行工具,因此不再需要使用Flask-Script,会产生包不兼容的问题。使用flask manage.py方式启动项目应该执行export FLASK_APP=manage.py,指定flask入口文件,另外,flask-sqlalchemy是flask的ORM工具,参考SqlAlchemy使用入门

风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。