简介
Flask框架 是基于WSGI工具箱编写的轻量级Web开发框架,WSGI工具箱中路由模块使用Werkzeug,模板引擎则使用Jinja2- 其没有默认使用的数据库,你可以选择
MySQL,也可以用NoSQL。 - 其本身相当于一个内核,几乎所有的功能都要用第三方模块扩展。
扩展包
Flask-SQLalchemy:操作数据库;
Flask-script:插入脚本;
Flask-migrate:管理迁移数据库;
Flask-Session:Session存储方式指定;
Flask-WTF:表单;
Flask-Mail:邮件;
Flask-Bable:提供国际化和本地化支持,翻译;
Flask-Login:认证用户状态;
Flask-OpenID:认证;
Flask-RESTful:开发REST API的工具;
Flask-Bootstrap:集成前端Twitter Bootstrap框架;
Flask-Moment:本地化日期和时间;
Flask-Admin:简单而可扩展的管理接口的框架
基本框架
设置视图
步骤:
- 导入
Flask包 - 实例化
Flask对象 - 定义视图函数并配置路由
- 启动
Flask框架
其中设置了Flask本身的属性,如静态文件及模板文件的储存路径和访问路径
视图函数
# 0.导入Flask类
from flask import Flask
# 1.实例化Flask对象,可传参数(import_name,static_url_path,static_folder,template_folder)
实例对象名 = Flask(__name__)
# 2.通过装饰器配置路由,并写视图函数
@app.route('为视图函数配置的路由', methods=[可填写多种请求方式])
def 视图函数名():
……
print(实例对象名.url_map) # 查看整个Flask应用的路由映射信息
……
return 返回值
# 3.自动启动Flask框架(也可以使用 python 文件名.py 启动框架)
if __name__ == '__main__':
实例对象名.run() # 可传参数(host、port、debug)
实例化对象
实例化时可传参数
import_name- 其决定 Flask 在访问静态文件时在那个包中查找
- 必传参数,一般传
__name__,表示当前文件所在包 - 若上传
python标准包名,则静态文件和模板文件会访问异常,视图函数可以正常访问
template_folder- 可以不传,默认为:
template_folder="templates" - 用于存储模板文件的文件夹名不是
templates
- 可以不传,默认为:
static_folder- 可以不传,默认为:
static_folder= "static" - 用于存储静态文件的文件夹名不是
static
- 可以不传,默认为:
static_url_path- 其决定 访问静态文件时
url的书写 - 可以不传,默认为:
static_url_path= "/" + static_folder,例:访问127.0.0.1:5000/static/1.png访问1.png到图片 - 若设置为:
static_url_path="/abc",则访问路径为:127.0.0.1:5000/abc/1.png
- 其决定 访问静态文件时
启动服务
-
视图文件中自启(
实例对象名.run())可选参数:
host="域名"启动服务所用的域名,默认使用127.0.0.1port=端口号启动服务所用的端口, 默认使用5000端口debug = True表示开启调试模式,debug = False表示关闭调试模式
调试模式的作用
- 程序代码修改后可以自动重启服务器
- 当服务器出现错误的时候,会将错误信息返回到前端展示
-
终端启动
在终端中输入:
$ export FLASK_APP=项目名称 $ flask run -h 指定IP -p 指定端口 -
Pycharm启动

某些旧版本

路由配置及查看:
配置路由格式:@Flask实例化对象.route('/正常路径/<转换器:参数变量名>', methods=["可填写", "多种", "请求方式"])
配置方式:作为装饰器配置在视图函数之上
查看Flask服务的所有路由:Flask实例化对象.url_map(在视图中使用)
配置路由
Flast框架中的路由配置不能使用正则表达式,因此Flast定义了六种转换器用来接收路径参数(动态路由)
- 配置格式:
/正常路径/<转换器:参数变量名> - 调用格式:直接使用
参数变量名 - 注意视图函数需要接受该
参数变量名
| 转换器 | 含义 | 用正则实现 |
|---|---|---|
string | 匹配任意无\路由 | [^\]+ |
path | 匹配任意包括\路由 | [^\]+.*? |
int | 匹配整数路由 | \d+ |
any(路由1,路由2) | 匹配括号中的任意一种路由 | - |
float | 匹配小数路由 | \d+\.\d+ |
uuid | 匹配一组UUID的路由 | - |
注意:
- 路由的填写必须加上最左侧的
/,并且不需要使用^$(区别于Django) - 如果路由规则以斜线结尾,当用户以不带斜线的形式请求,用户被自动重定向到带有结尾斜线的相同页面。
如果路由规则结尾没有斜线,当用户以带斜线的形式请求,会抛出一个 404 not found 。 - 默认为使用
string转换器,即将该位置的数据以字符串格式进行匹配 - 转换器会将其数据类型一同转换,即
<int:id>获得的id数据类型为int Flask实例化对象.url_map的返回结果为:一个Map对象,其中有一个_rules属性包含了多个Rule类型对象,Rule中存有路由、视图名、请求方式等,
demo
@app.route('/users/<int:user_id>') # 使用int转换器进行路径传参
def user_info(user_id): # 视图函数需要接受该路径参数
print(type(user_id)) # 直接使用参数名调用传参数据
return '传来的路径参数为:'+ user_id
转换器的实现原理:
- 在转换器类中通过
regex="正则表达式"来定义路由的正则匹配规则 - 将 转换器类与转换器名 以键值对的形式 配置到转换器字典
DEFAULT_CONVERTERS = { 'default': UnicodeConverter, 'string': UnicodeConverter, 'any': AnyConverter, 'path': PathConverter, 'int': IntegerConverter, 'float': FloatConverter, 'uuid': UUIDConverter, } - 将转换器字典作为 路由规则对象(
Map) 的属性(converts属性名) - 使用
@app.router("/正常路径/<转换器:参数变量名>")调用转换器
自定义转换器
根据转换器的实现原理获得自定义转换器的步骤:
- 定义转换器类,继承自
BaseConverter,重写regex属性的正则表达式
from werkzeug.routing import BaseConverter
class MobileConverter(BaseConverter):
"""手机号格式转换器"""
regex = r'1[3-9]\d{9}' # 注意regex属性名为固定的
2. 将自定义的转换器配置到Flask应用中
app = Flask(__name__)
# 将自定义转换器添加到转换器字典中,并指定转换器使用时名字为: mobile
app.url_map.converters['mobile'] = MobileConverter
- 在使用转换器是正常调用(
@实例对象名.router("/正常路径/<转换器名:参数变量名>"))
@app.route('/sms_codes/<mobile:mob_num>')
def send_sms_code(mob_num):
return 'send sms code to {}'.format(mob_num)
类视图
视图函数弊端:无论什么请求方式都运行该的视图函数,若要实现GET、POST、DELETE、PUT请求方式分别对应不同的功能必须进行if request.method = "请求方式"判断
继承自View类
定义类视图
class 类名(View):
methods = ['各种','请求方式','需大写']
decorators = [添加装饰器名]
def dispatch_request(self, 可接受路径参数):
return 响应数据
在Flask应用中添加路由,并自动调用dispatch_request方法
Flask实例对象.add_url_rule('/正常路径/<转换器:参数变量名>', view_func=类名.as_view('类名全小写'))
该类视图拥有与视图函数一样的弊端,因此对使用继承自MethodView的类视图
继承自MethodView(常用)
新建一个视图函数文件views.py,定义类视图,继承自MethodView类
class 类名(MethodView):
def get(self):
return 响应数据
def post(self, 可接受路径参数):
# 接受其他参数,具体见下文
return 响应数据
注册至Flask应用中
Flask实例对象.add_url_rule('/正常路径/<转换器:参数变量名>', view_func=类名.as_view('类名全小写'))
蓝图模式
蓝图模式(Blueprint):模块化组织管理,将一个独立的功能封装成一个模块单元(类似于Django中的子应用,利于代码复用)
注意:
- 一个应用可以具有多个蓝图
- 可以将一个蓝图注册到任何一个未使用的URL下比如
/user、/goods作为默认其实路由 - 蓝图可以具有自己的模板、静态文件、操作方法,但是其并不是一个完整的应用,不能独立运行,必须要注册到应用中。
- 在一个应用初始化时,就应该要注册需要使用的蓝图
新建蓝图步骤:
- 在项目路径下新建一个
Python Package(例:user),并在包中新建一个视图文件(例view.py) - 在
Python Package下的__init__文件中创建蓝图对象,用于构建视图的路由from flask import BluePrint # 创建蓝图对象(实例化对象名一般使用蓝图名_bp)应用名一般填写__name__ 并配置视图前缀路由 蓝图实例对象名=Blueprint('蓝图名',应用名, url_prefix='蓝图路由前缀') # 将视图文件导入__init__文件中,并且在创建蓝图之后,因为视图中会用到蓝图对象,否则会循序导包 from . import views - 在视图文件中定义类视图或视图函数
# 导入蓝图对象 from . improt 蓝图实例对象名 # 定义类视图 class 类名(MethodView): def get(self): return 响应对象 蓝图实例对象.add_url_rule('/正常路径/<转换器:参数变量名>', view_func=类名.as_view('类名全小写')) # 真是路由为:/蓝图路由前缀/正常路径/<转换器:参数变量名> @蓝图实例对象.route('/正常路径/<转换器:参数变量名>') def 函数名(参数变量名): return 响应对象 - 将蓝图注册到
Flask主应用或工厂函数中Flask实例对象名.register_blueprint(蓝图实例对象名)
蓝图内部静态文件
蓝图对象创建时不会默认注册静态目录的路由。需要我们在 创建时指定 static_folder参数。
下面的示例将蓝图所在目录下的static_admin目录设置为静态目录
admin = Blueprint("admin",__name__,static_folder='static_admin')
app.register_blueprint(admin,url_prefix='/admin')
现在就可以使用/admin/static_admin/<filename>访问static_admin目录下的静态文件了。
也可通过static_url_path改变访问路径
admin = Blueprint("admin",__name__,static_folder='static_admin',static_url_path='/lib')
app.register_blueprint(admin,url_prefix='/admin')
蓝图内部模板目录
蓝图对象默认的模板目录为系统的模版目录,可以在创建蓝图对象时使用 template_folder关键字参数设置模板目录
admin = Blueprint('admin',__name__,template_folder='my_templates')
配置参数
作用:集中管理配置Web应用工程的相关配置信息(类似Django中的settings.py)
比如:
- 数据库的连接信息
- 日志的配置信息
- 自定义的配置信息……
注意:所有配置项名要求字母大写
从配置对象中加载
- 加载配置对象:
Flast实例对象名.config.from_object(配置类名) - 使用配置类中的配置项:
Flast实例对象名.config.get("配置项名") - 特点:可以实现代码复用,但不安全
新建配置文件config.py
class DefaultConfig(object):
"""默认配置"""
DEBUG=None
SECRET_KEY = 'TPmi4aLWRbyVq8zu9v82dWYW1'
class DevConfig(DefaultConfig):
"""调试环境下的配置,继承默认配置类"""
DEBUG=True
class ProdConfig(DefaultConfig):
"""上线环境下的配置,继承默认配置类"""
DEBUG=True
# 建立字典映射,便于修改,仅修改字典键即可,不必修改导入文件的包
config_dict = {
"dev":DevConfig,
"prod":ProdConfig
}
在Flask文件中配置(在实例化之后)和 视图中调用
from config import config_dict
app = Flask(__name__)
# 加载配置对象
app.config.from_object(config_dict['dev'])
@app.route("/")
def index():
# 使用配置类中的配置信息
print(app.config['SECRET_KEY'])
return "hello world"
从配置文件中加载
- 加载配置文件:
Flast实例对象名.config.from_pyfile(配置文件名) - 使用配置文件中的配置信息:
Flast实例对象名.config["配置信息名"]
注意:
新建一个配置文件config.py,直接书写配置项(不定义类)
SECRET_KEY = 'TPmi4aLWRbyVq8zu9v82dWYW1'
在Flask文件中配置(在实例化之后)和 视图中调用
app = Flask(__name__)
# 加载配置文件
app.config.from_pyfile('config.py')
@app.route("/")
def index():
# 使用配置文件中的配置信息
print(app.config['SECRET_KEY'])
return "hello world"
从环境变量中加载
环境变量(environment variables)一般是指在操作系统中用来指定操作系统运行环境的一些参数,如:临时文件夹位置和系统文件夹位置等。 环境变量是在操作系统中一个具有特定名字的对象,它包含了一个或者多个应用程序所将使用到的信息。
- 通俗的理解,环境变量就是我们设置在操作系统中,由操作系统代为保存的变量值
- Flask使用环境变量加载配置的本质是通过环境变量值找到配置文件,再读取配置文件的信息
- 应用场景:配置文件的地址不固定;在代码中不想暴露真实的配置文件地址,只在运行代码的服务器上才有真实配置文件的信息。
- 特点:使用复杂,相对安全,不包含在代码内,配置项容易查询不到
在Linux系统中设置和读取环境变量的方式如下:
export 变量名=变量值 # 设置 例:export ITCAST=python
echo $变量名 # 读取 例:echo $ITCAST
其在Flast文件加载和视图中使用方式为:
# 加载环境变量配置项 环境变量的值为配置文件的绝对路径
Flast实例化对象名.config.from_envvar('环境变量名')
# 使用配置项
Flast实例化对象名.config['SECRET_KEY']
demo
- 先在终端中执行如下命令
export PROJECT_SETTING='~/setting.py' - 再配置到
Flask视图运行如下代码app = Flask(__name__) # 从环境变量中加载配置项 app.config.from_envvar('PROJECT_SETTING', silent=True) @app.route("/") def index(): print(app.config['SECRET_KEY']) return "hello world"
关于silent的说明:
- 表示系统环境变量中没有设置配置项时是否抛出异常
False表示不安静的处理,没有值时报错通知,默认为FalseTrue表示安静的处理,即时没有值也让Flask正常的运行下去
Pycharm运行时设置环境变量的方式:


工厂模式(项目中常用)
工作时多使用工厂模式:创建工厂文件和配置文件,并结合使用配置对象与环境变量加载配置
新建一个配置文件config.py
class DefaultConfig(object):
"""默认配置"""
SECRET_KEY = 'TPmi4aLWRbyVq8zu9v82dWYW1'
class DevConfig(DefaultConfig):
"""调试环境下的配置,继承默认配置类"""
debug = True
class ProdConfig(DefaultConfig):
"""上线环境下的配置,继承默认配置类"""
debug = False
在终端定义环境变量配置项
export 变量名=变量值 # 设置 例:export ITCAST=python
echo $变量名 # 读取 例:echo $ITCAST
再新建一个工厂文件flast_factory.py(将Flast实例化、导入配置文件和注册蓝图等封装)
def create_flask_app(config):
"""
创建Flask应用
:param config: 配置类对象,便于使用不同的配置类,避免过多修改代码
:return: Flask应用
"""
app = Flask(__name__) # 实例化Flask对象
# 从配置文件中导入配置项
app.config.from_object(config)
# 从环境变量中导入配置项
app.config.from_envvar("PROJECT_SETTING", silent=True)
# 注册自定义转换器,应在注册蓝图之前,否则蓝图中无法使用自定义的装换器
app.url_map.converters['mobile'] = MobileConverter
# 注册类视图路由和蓝图
user_bp.add_url_rule('/正常路径/<转换器:参数变量名>', view_func=类名.as_view('类名全小写'))
app.register_blueprint(user_bp))
return app # 返回Flask对象(加有配置项)
在Flask主应用文件中调用工厂函数
if __name__ == '__main__':
# 调用工厂函数
app = create_flask_app(DevConfig)
app.run()
注意:
- 使用配置项,多是通过
Flask实例化对象.config获取,结果为字典,可以使用[键]取值也可以使用.get(键),但推荐使用后者(无值不报错) - 后配置的 配置项数据 会覆盖掉 先配置的同名配置项数据(例后注册的环境变量中的配置覆盖掉先注册的配置文件中的配置项)
视图函数的请求与响应
接收参数
导入request
from flask import request
格式:request.flask属性(路径参数除外)
| 参数 | flask属性 | 注意点 | django属性 |
|---|---|---|---|
| 查询参数 | args | 结果为字典,可以使用.get(键)和[键]取数据 | GET |
| 请求报文头 | headers | 结果为字典,可以使用.get(键)和[键]取数据 | META |
| 请求体-表单 | form | POST | |
| 请求体-json对象 | data | 返回为字节流,需经过json.loads(request.data.decode()),方才为字典 | body |
| 路径参数 | 转换器 | 定义视图函数时必须接受 | 正则表达式 |
request其余属性 | 作用 |
|---|---|
method | 记录请求使用的HTTP方法 |
url | 记录请求的URL地址 |
files | 获取请求上传的文件 |
常用的返回响应对象
在前端使用jinja2模板
返回模板
- 导入
render_template - 在视图函数或方法中返回
格式:render_template("模板文件路径及名称",向模板中传递的参数1, 参数2,……)
from flask import render_template
@app.route('/')
def index():
return render_template('index.html', my_str=mstr, my_int=mint)
- 前端
index.html中使用方法
{{ my_str }},{{ my_int }} , {{ request.method }} # 不用传request,前段可以直接用
返回JSON对象
- 导入
jsonify - 在视图函数或方法中返回字典
格式:jsonify(python字典型数据)
from flask import jsonify
@app.route('/demo2')
def demo3():
json_dict = {
"user_id": 10,
"user_name": "laowang"
}
return jsonify(json_dict)
路由重定向
导入redirect
在视图函数或方法中返回路由
格式:redirect('url')
from flask import redirect
@app.route('/demo3')
def demo2():
return redirect('http://www.baidu.com')
返回原始response对象
格式:make_response(字符串),还可以添加属性
@app.route('/demo4')
def demo4():
resp = make_response('make response测试')
resp.status = “404 not found”
return resp
返回元祖
元组必须是(response,status,headers)的形式,并且至少包含一个元素
status值会覆盖状态代码headers可以是一个列表或字典,作为额外的消息标头值。
@app.route('/demo5')
def demo5():
# return '状态码为 666', 666
# return '状态码为 666', 666, [('IT', 'Python')]
return '状态码为 666', 666, {'IT': 'Python'}
状态保持
Cookie
Cookie是存储在浏览器中的一段纯文本信息,建议不要存储敏感信息如密码,不安全。Cookie以键值对Key-Value形式进行信息的存储。Cookie基于域名安全,不同域名的Cookie是不能互相访问的
设置Cookie:
response对象.set_cookies("键", "值", max_age=有效时间)
读取Cookie:
变量名 = request.cookies.get('键')
删除Cookie
response对象.delete_cookie('username')
注意:
- 有效时间默认为:会话结束,即关闭浏览器后会失效
- 设置有效时间时,单位是秒,例:
max_age= 60 * 60 * 24表示一天 - 有效时间可以设置为负数,表示用完即失效
Session
Flask框架的Session是存放在Cookie中,因其默认不连接数据库。
导入Session:from flask import Session
设置Session需要配置秘钥
# 1. 从配置对象中加载
class DefaultConfig(object):
SECRET_KEY = "自定义一段复杂的字符串(任意字符)"
app.config.from_object(DefaultConfig)
# 2.直接设置
app.secret_key='自定义一段复杂的字符串(任意字符)'
设置Session
session['键'] = '值' # 会使用秘钥和算法自动加密
读取Session
变量名 = session.get('键')
同一异常处理
统一处理指定状态异常
-
主动抛出异常
格式:abort (指定状态码)例:abort(404)
注意:只能抛出 HTTP 协议的错误状态码(4系列或5系列的HTTP 状态码) -
捕获并处理抛出的异常
定义处理异常函数,并为其添加errorhandler装饰器@Flask实例对象.errorhandler(给定状态码) def 处理异常函数名(e): …… return xxx
统一处理指定错误异常
例:统一处理除数为0异常
@app.errorhandler(ZeroDivisionError)
def zero_division_error(e):
return '除数不能为0'
申请钩子
在客户端和服务器交互的过程中,有些准备工作或扫尾工作需要处理
比如:
- 在请求开始时,建立数据库连接;
- 在请求开始时,根据需求进行权限校验;
- 在请求结束时,指定数据的交互格式;
作用:为了让每个视图函数避免编写重复功能的代码
实现形式:通过装饰器的形式实现
Flask支持如下四种请求钩子:
before_first_request
在处理第一个请求前执行(仅跟随服务器开启时执行一次)
可以在此方法内部做一些初始化操作before_request
在每次请求前执行执行
这时候已经有请求了,可以在此方法中做请求的校验
如果请求的校验不成功,可以直接在此方法中进行响应,直接return 响应,之后不会执行路由指定的视图函数after_request
在执行完视图函数之后会调用,若抛出服务器内部异常,则不会执行(自己主动抛出的异常,仍会执行)
必须将视图函数所生成的响应传入此方法,可以在此方法中对响应做最后一步统一的处理
最后将处理后的响应返回teardown_request
在每次请求后执行
接受一个参数:错误信息,如果有相关错误抛出
代码测试
from flask import Flask
from flask import abort
app = Flask(__name__)
# 在第一次请求之前调用,可以在此方法内部做一些初始化操作
@app.before_first_request
def before_first_request():
print("before_first_request")
# 在每一次请求之前调用,这时候已经有请求了,可能在这个方法里面做请求的校验
# 如果请求的校验不成功,可以直接在此方法中进行响应,直接return之后那么就不会执行视图函数
@app.before_request
def before_request():
print("before_request")
# if 请求不符合条件:
# return "laowang"
# 在执行完视图函数之后会调用,并且会把视图函数所生成的响应传入,可以在此方法中对响应做最后一步统一的处理
@app.after_request
def after_request(response):
print("after_request")
response.headers["Content-Type"] = "application/json"
return response
# 在每一次请求之后都会调用,会接受一个参数,参数是服务器出现的错误信息
@app.teardown_request
def teardown_request(response):
print("teardown_request")
@app.route('/')
def index():
return 'index'
if __name__ == '__main__':
app.run(debug=True)
在第1次请求时的打印:
before_first_request
before_request
after_request
teardown_request
在第2次请求时的打印:
before_request
after_request
teardown_request
上下文对象
不用创建,导入后直接使用(from flask import 上下文对象)
注意:
- 上下文对象是伴随请求而生,伴随响应而灭,即仅能在视图中使用
- 若想在非视图中使用,必须手动推送
- 每个请求,都有各自的上下文对象,相互隔离
请求上下文
request
封装了HTTP请求的内容,针对的是http请求。
举例:user = request.args.get('user'),获取的是查询参数。
Session
用来记录请求会话中的信息,针对的是用户信息。
举例:session['name'] = user.id,可以记录用户信息。或通过session.get('name')获取用户信息。
应用上下文
作用:帮助 request获取当前的Flask应用对象 ,便于在视图使用
current_app
current_app就是当前运行的flask实例化对象,在代码不方便直接操作flask实例化对象时,可以操作current_app就等价于操作flask实例化对象
其中存储了应用程序中的变量
例如:
current_app.config查看配置项- 查看连了的数据库
- 有哪些
public的工具类、常量 current_app.name查看当前flask实例化对象的名称 ……
g对象
g 对象:是flask框架 的一个全局的临时变量,主要充当中间媒介,实现多个视图函数之间的数据共享
**使用场景:**在一次请求内调用多个视图函数间传递一些数据。每次请求都会重设这个变量。
手动推送上下文
实现在视图函数之外使用上下文对象
请求上下文
request_context为我们提供了请求上下文环境,允许我们在外部使用请求上下文request和session对象
可以通过with语句进行使用
with app.request_context():
使用request对象和session对象
应用上下文
app_context为我们提供了应用上下文环境,允许我们在外部使用应用上下文current_app和g对象
可以通过with语句进行使用
with app.app_context():
使用current_app对象和g对象
注意:在视图函数之外使用request对象时,没有请求,无法获取前端传来参数,因此需要自己构建假的请求数据
# 模拟解析客户端请求之后的wsgi字典数据
environ = {'wsgi.version':(1,0), 'wsgi.input': '', 'REQUEST_METHOD': 'GET', 'PATH_INFO': '/', 'SERVER_NAME': 'itcast server', 'wsgi.url_scheme': 'http', 'SERVER_PORT': '80'}
with app.request_context(environ): # 借助with语句使用request_context创建请求上下文
print(request.path)
本文详细介绍了Python的Flask框架,包括基本框架的设置、视图函数、蓝图模式、配置参数、请求与响应处理、状态保持以及异常处理等方面。通过实例展示了如何实例化对象、配置路由、使用类视图、处理Cookie和Session,以及如何实现统一异常处理和请求钩子。同时,文章提到了Flask中常用的扩展包和如何进行模块化管理,适合对Flask感兴趣的开发者参考学习。
1156

被折叠的 条评论
为什么被折叠?



