Flask入门

发布时间 2023-04-02 22:40:08作者: leethon

Flask入门

常见python-web框架:

django:大而全的web框架,自己内置了很多app,第三方适配的模块也多,但由于过于全,在开启小项目时,略显臃肿。

flask:小而精的python-web框架,甚至可以在一个py文件中完成web最基础的功能,而完成更丰富的功能则需要借助第三方模块。

web.py:是一个小巧灵活的Python框架,它简单而且功能强大(国内几乎没有用的)

常见的异步web框架:

fastapi:python的异步web框架,不少公司在用,专门做前后端分离用于写接口

https://fastapi.tiangolo.com/zh/

sanic:python的异步web框架,供支持异步高并发请求的 web 服务

https://sanic.dev/zh/

tornado:异步框架,用的比较少了:

https://www.tornadoweb.org/en/stable/

这里需要强调所谓同步框架和异步框架,是有本质上的区别的:

同步框架并不代表没有使用异步,而是对于处理请求到返回响应的过程是同步的,一个线程只能处理一个请求,请求在响应前一直占据此线程。同步框架项目也会有异步并发,如django就可以同时处理多个请求(虽然并发量很小)是通过网关服务器实现的。

异步框架则可以灵活的调度线程,当处理请求的过程中出现了IO等阻塞操作,就会将当前线程重新分配用于处理其他请求,可以非常显著的提高cpu的利用率和并发量。

简单来说:

  • 同步框架的一个线程只能处理一个请求
  • 异步框架的一个线程可以处理多个请求

flask简介

Flask是一个基于Python开发并且依赖jinja2模板和Werkzeug WSGI服务的一个微型框架。

jinja2是支持模板语法的模块,可以用于在html文档中用特殊的模板语法进行插值渲染,主要用于前后端混合的项目。

Werkzeug WSGI 符合wsgi协议的web服务器,与django使用的wsgiref是不同的web服务器。

Hello World

from flask import Flask

app = Flask(__name__)  # 初始化app

@app.route('/')  # 注册路由
def index():  # 视图函数
    return 'hello world'

if __name__ == '__main__':
    app.run()  # 启动项目

前后端混合项目演示

这个小项目用了古老的表单标签(使用form标签可以发送post请求的特性)。

html模板文件

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<form method="post">
    <input type="text" name="num1"> +
    <input type="text" name="num2"> = {{summary}}
    <input type="submit" value="计算"> {{error}}
</form>
</body>
</html>

py文件(项目后端)

from flask import Flask, request, render_template

app = Flask(__name__)

# 根路径
@app.route('/', methods=['GET', 'POST'])
def index():
    # flask不需要传入request对象,使用全局的request
    if request.method == 'GET':
        return render_template('login.html')  # 返回模板
    else:
		if num1.isdigit() and num2.isdigt():
            return render_template('sum.html',summary=int(num1)+int(num2))
        else:
            return render_template('login.html', error='输入的不是纯数字')  # 注意跟django的render区分,要模板渲染的数据,直接key=value传即可

首先浏览器按照路由发送get请求拿到html文件,在页面中,输入两个数字,点击提交,则会向本地址(相同路由)发送post请求,再进入post的分支,携带插值变量渲染html模板返回前端。

flask基础

  1. 注册路由可以通过装饰器app.route(路径,methods=[请求方式,'get','post']),加装在某个函数上,这个函数就是视图函数了,路径中可以使用转换器动态匹配路由

  2. 视图函数必须返回响应内容,基础的有:

    • render_template 按模板返回
    • redirect 重定向到其他路由
    • 字符串 与django的HttpResponse类似
    • jsonify 返回json格式字符串(内部可以填入列表,字典等)
  3. 请求的request对象,是全局的,直接导入使用即可,在不同视图函数中不会混乱

  4. session 全局的,直接导入使用即可

    要使用session前一定要指定秘钥app.secret_key = '越复杂越好'

  5. 模板渲染使用的jinjia2,比django的模板语法更强大,可以加括号传参调用,还可以使用中括号取值等。

flask配置方式

flask有多种配置方式,在此罗列一下:

  1. flask对象app=Flask()中,可以app.debugapp.secret_key,配置debug和秘钥

    app.config['配置键'] = 配置值可以设置其他配置项

  2. 使用py文件导入(类似于django的settings.py)

    app.config.from_pyfile("settings.py")
    

    类似于django项目中的策略,但在flask中还有更好的方案。

  3. (常用)导入类配置项

    ## settings.py
    class ConfigBase:
        DEBUG=False
        一些配置项。。。
    
    class DevConfig(ConfigBase):
    	DEBUG=True   # 开发环境中debug为true
        mysql=测试库   # 开发时用测试库
        
    class ProdConfig(ConfigBase):
    	mysql=上线库  # 实际上线用不一样的库配置
        
        
    ## 导入配置
    app.config.from_object('settings.DevConfig')
    
  4. 其他:

    # 通过环境变量配置
    app.config.from_envvar("环境变量名称")
    # 通过json文件配置
    app.config.from_json("json文件名称")
    # 通过字典格式配置
    app.config.from_mapping({'DEBUG': True})
    

    字典格式配置在一些大型公司中会用到,因为会建立大的配置中心,多台机器可能都使用这个配置中心的配置,启动时先朝配置中心发送一个请求,它会返回一个字典(验证通过时),方便我们做集群化部署等。

对于项目的配置,我们可以定义为,供给给项目启动后自动加载的不再变化的量。而这些配置可以是flask的内置配置字段,用于支持flask的web服务,也可以是其他模块的配置字段,如redis、mysql的连接地址等。

路由系统

写法及原理

flask配置路由的基础写法是装饰器:

@app.route('/')
def index():
    pass

也就是将index这个普通函数替换成了带路由的视图函数。按照有参装饰器的语法糖,index被替换为app.route('/')(index),查看route的源码,即被替换成了decorator(index)这个闭函数。

其内部最核心的就只执行了self.add_url_rule(rule, endpoint, f, **options),而self在这个语境中是flask的对象app。

所以flask路由的本质是app对象的add_url_rule完成路由的注册

add_url_rule的参数

rule 匹配的规则(路径,可能含转换器)
view_func  视图函数,即被装饰的函数
defaults = None  视图函数可能会需要一些额外的参数,通过defaults = {'k': 'v'}提供
 endpoint = None  路径的别名,名称,用于反向解析URL,反向解析用到一个函数url_for('endpoint名称')
 methods = None  允许的请求方式,如:["GET", "POST"]

strict_slashes = None  对URL最后的 / 符号是否严格要求
redirect_to = None  访问这个路由相当于重定向到redirect_to

转换器

路由中可能包含一些视图函数所需的参数,通过转换器对路由的某一部分进行动态匹配并传参给视图。

使用方式:

@app.route('/student/<int:pk>')

@app.route('/media/<path:path>')

转换器的格式为<转换器类型:匹配内容的变量名>

转换器类型有:

转换器 说明
default UnicodeConverter
string UnicodeConverter
any AnyConverter
path PathConverter
int IntegerConverter
float FloatConverter
uuid UUIDConverter