flask本身是一个内核,其他几乎所有的功能都要用到扩展(邮件扩展Flask-Mail,用户认证Flask-Login),都需要用第三方的扩展来实现。比如可以用Flask-extension加入ORM、窗体验证工具,文件上传、身份验证等。Flask没有默认使用的数据库,可以选择MySQL,也可以用NoSQL。其WSGI工具箱采用Werkzeug(路由模块),模板引擎则使用Jinja2(flask的核心即Werkzeug和Jinja2)。
from flask import Flask # 导入flask模块中Flask类
app = Flask(__name__) # 创建Flask实例,即flask应用对象,__name__会设置为当前活动模块的名字,此处使用__name__意为设置项为默认值,即将当前文件所在的目录设为根目录,以当前目录下的static目录为静态文件目录,以当前目录下的templates为模板文件目录
@app.route(‘/’) # route的作用是将其后输入的URL与下面的函数关联,即当一个指向URL’/’的请求到达服务器时,route会安排Flask web服务器调用下面的hello函数并将输出返回给服务器,服务器将其返回给浏览器。
def hello() -> str:
return 'Hello world from Flask!'
app.run() # 使Web服务器开始运行,是flask自带的测试用服务器
在浏览器网址中输入127.0.0.1:5000,其中127.0.0.1是本地IP(也叫localhost),5000是Flask的测试协议端口。
import_name=__name__ # 设置根目录,也随之确定默认的静态文件和模板文件目录
static_url_path='/qq' # 访问静态文件的url前缀,默认为'/static'
static_folder='static' # 访问静态文件的目录,可以使用'/static'指定绝对目录,相对目录是相对当前目录
template_folder='templates' # 访问模板的目录,与static_folder类似)
flask配置参数的方式:
①使用配置文件,app.config.from_pyfile(‘config.cfg’),在当前目录下寻找配置文件;
②使用对象配置参数,一般使用配置类属性,如:
class Config:
DEBUG = True
app.config.from_object(Config)
③直接操作config字典,app.config[‘DEBUG’]=True;
注:app.config是一个字典,其可以设置也可以获取参数,Ⅰapp.config.get(‘xx’)可以在函数中获取自定义的配置参数(非flask使用);Ⅱ在flask中存在一个current_app对象,其可以理解为当前app对象的代理人,current_app.config.get(‘xx’)也可以获取参数。
flask设置IP与端口:
app.run(host=‘0.0.0.0’, port=5000, debug=True)'0.0.0.0’意为当前主机IP都可以访问,debug参数在此处也可以设置。
flask设置限制视图函数的访问方式:
@app.route(’/’, methods=[‘POST’]),若不添加此参数,则默认允许GET,OPTION,HEAD方式访问(不包含POST,PUT,DELETE等修改操作)。
路由即从一个接口上收到信息,通过映射关系将其传递给另一个应用,如app.route装饰器,将url与相应函数连接起来,完成了路由功能。
查看所有路由路径:app.url_map,以列表的形式返回路由的映射方式和限制访问方式。
路径与视图函数的多重对应:①当一个路径对应的多个视图函数名和访问方式都相同时则按照url_map的顺序访问最上方的视图函数;②当多个路径对应一个视图函数时在视图函数上添加多个装饰器。
重定向与URL的反向解析:①flask中有方法redirect,其与Django中的redirect用法类似,redirect('/index')
即可重定向至指定的url;
②flask中有方法url_for,与Django中reverse用法类似,但不专门指定name参数,而是使用视图函数名,redirect(url_for('index'))
;
URL的自定义与参数获取:Flask中不支持url直接使用正则匹配,而是采用了转换器的形式,其默认提供的转换器如图所示:
使用时app.route('/index/
其中int为转换器名,id为设置的参数名,此参数名需要传入视图函数中,当没有冒号时默认转换器为string并将<>中的内容视作参数名;
flask中url转换器的自定义:如下图所示:
①导入转换器基类;②自定义转换器类继承基类,并在其中重写__init__方法;③将自定义的转换器类添加进url_map的converters字典中并命名;④在视图函数中使用自定义的万能转换器,同时传入正则与参数名即可进行匹配。
flask中使用转换器的流程:如下图所示:
①对url_map中转换器字典中的转换器类创建实例,根据其重写的初始化方法传入自定义的正则表达式作为regex;
②进行正则匹配(该过程由flask完成与下述函数无关),将匹配到的值(即转换器使用参数名标识的值,每一个转换器都只能传递一个参数)传入转换器类中的to_python方法,to_python方法中可以对值进行操作(类型变换等),然后将值直接传入视图函数(url匹配和转换器值转换的过程已经完成,此处直接将最终的value传入视图函数作为参数);
③如果使用url反向解析,则对于要求参数的路径需要在url_for中传入参数,此处传入的参数就通过to_url方法组织成完整的url再进行①②操作,这个参数可以在to_url中修改。
注:url_for方法中传入参数名必须与要重定向的url中自定义的参数名相同。
关于表单格式数据:即形如’a=1&b=2’的字符串,称为表单格式数据,其只要在请求体中出现,就使用form属性解析(注意与下述args区分)。
在flask中,由前端传送的数据,其都通过一个全局变量request(关于request对象的具体介绍见后述)获取,其保存了当前请求的所有信息,常用属性如下:
data,记录请求中的数据(不包含查询字符串和表单格式数据)如json格式,并转换为字符串;
form,记录请求中的表单数据,类型为MultiDict,是一个类字典对象;
args,记录请求中的查询字符串QueryString,即url中的参数(如’/index?a=1&b=2’),是一个类字典对象;
cookies,记录请求中的cookie信息,类型为Dict;
headers,记录请求中的报文头部信息,类型为EnvironHeaders;
method,记录请求使用的HTTP方法,如GET/POST等;
get_json(),将json格式数据解析为字典并返回;
url,记录请求的url地址,类型为string;
path,记录用户的请求路径;
files,记录请求上传的文件,是文件对象(字节流),可以直接使用read/write方法,flask中对files提供了一个简单的保存方法
request.files.get('xx').save('路径url')
直接保存;
remote_addr,运行Web浏览器的IP地址;
user_agent,提交数据的浏览器的标识;
注:①可以使用postman来模拟浏览器请求,是一个常用的测试工具;
②request.url/path/url_for(‘index’)返回值的区别如下:
request.url: ‘http://127.0.0.1:5000/index’
request.path: ‘/index’
url_for(‘index’): ‘/index’
①abort函数:from flask import abort
,abort函数在flask中用于处理异常信息,其会立即终止视图函数的运行并返回一个状态码或一个Response对象,如abort(404),这个状态码必须是标准的状态码;或abort(Response(‘xxx’)),使用Response返回。
②自定义错误处理方法:flask提供了一个自定义错误处理的装饰器@app.errorhandler(404),其接收一个状态码,其下的视图函数def error(e):必须有一个错误信息的参数,即当出现404错误时就执行定义的error视图函数。
①使用return直接返回:flask中会对视图函数的返回值进行解析(不添加括号时会自动补充括号作为元组) ,完整状态为一个元组return (响应体,'状态码 自定义状态信息',响应头)
;其中响应体一般为一个字符串,状态码可以是不标准的状态码并可以附带自定义的状态码解释信息,响应头接收一个字典或由二维元组组成的列表,即{'自定义响应头': '内容'}
或[('x1', 'y1'), ('x2', 'y2')]
(其中响应头可省略,状态码在没有响应头时可省略);
②使用make_response函数:
from flask import make_response
res = make_response('响应体')
res.status='自定义状态码 自定义状态信息'
res.headers['自定义响应头']='内容'
return res
即创建一个响应实例,定义其属性并返回;
③使用jsonify函数:
from flask import jsonify
...
return jsonify(dict)
可以自动将字典转换为json字符串(json格式数据即一个特殊的字符串,在python中使用json模块的dumps()生成,loads()解析为字典)并自动设置响应头信息(Content-Type: application/json),常用形式如下:
return jsonify(errno=RET.DATAERR, errmsg="短信验证码错误", data={'a': xxx})
。
注:①无论是Ajax请求还是普通请求,其对于flask后端来说都是相同的请求,只不过Ajax请求一般会采用application/json格式来返回数据,其都有其状态码/自定义状态信息、响应头、响应体,在普通返回即元组或make_response方式返回时会设置,在jsonify返回时只设置响应体而响应头、状态码都由该方法自动完成,也可以return (响应体,'状态码 自定义状态信息',响应头)
在这个响应头中设置content-type,返回的也可以是json数据;
②在flask中,除了可以使用set_cookie方法在make_response对象中设置cookie,也可以通过设置响应头中'Set-Cookie': 'qwer=1234'
方式来设置cookie,其与响应数据类型无关,只要设置为此浏览器就会在前后端同源情况下将cookie设置到浏览器中;
③如果使用全局变量session设置了session,则其会自动在响应头中添加'Set-Cookie'
条目,并设置到浏览器中。
关于cookie与session详见前文Django视图简介部分。
①设置与获取cookie:
res = make_response(xx)
res.set_cookie('键', '值', max_age=3600s)
即在make_response对象中设置,默认有效期为浏览器关闭失效,获取时使用request.cookies.get('key')
,删除时依然使用make_response对象,res.delete_cookie('key')
;
②设置与获取session:
flask中的session是一个全局变量对象且其需要一个SECRET_KEY,在flask中使用session的流程:
from flask import session
app.config['SECRET_KEY']='xxx'
@app.route()
def session_test():
session['key']='value',# 设置session
session.get('key'), # 获取session
session.clear(); # 删除session
③flask的session机制:其默认将所有session数据保存在cookie数据中(使用SECRET_KEY进行加密),在后端调用时进行解密并获取数据;
④session的保存方式:cookie(flask默认方式),关系与非关系型数据库,文件,内存中,session的保存方式可自行设置,一般会使用redis数据库。
注:①cookie删除时本质上就是把cookie的过期时间设置为跟创建时间相同,然后浏览器检测时清除(后端没有直接操作浏览器中cookie的方法);
②cookie创建本质上是在响应头中添加Set-Cookie:‘key’=‘value’,浏览器根据响应头信息添加cookies;
③session可以不借助cookie而存在,其可以在重定向时直接将sessionid放置于url参数中,在视图函数中对sessionid进行解析,获取数据,但此种方式无法设置session的有效期(由于一些浏览器的隐私设置可能禁用cookie)。
①与Django不同,flask中的render_template(返回一个HTML字符串),redirect(直接指向另外的视图函数),都不是make_response对象,因此若想在其中设置cookie,
res = make_response(render_template(..))
res.set_cookie(..)
不能直接对render_template对象设置;
②flask提供了一个名为escape的函数,可以将提供的原始数据转换为HTML转义的等价形式,它返回一个Markup对象,在HTML中,将’<’定义为’<’,将’>’定义为’>’(还有其他的转义字符),可以将返回的Markup对象当做一个普通的字符串。
①请求上下文对象:flask通过上下文对象来实现request对象在多线程中的特殊性(即多线程共用代码共享全局变量时,request对象依然为每个线程维护不同的内容),使用线程局部变量的形式来实现,如图所示,采用嵌套字典的形式,flask在获取时自动对线程的编号进行识别,不同线程中request的属性属于同一个全局变量,将flask中的这种对象统称为请求上下文对象,如request, session;
②应用上下文对象:
current_app,视为当前视图函数所在应用的代理人,current_app也是全局变量,其跟用户请求无关,但与当前应用有关;
g对象,是一个全局变量,是flask提供的专用于临时存储的对象,其可以添加属性,在一次请求中保持,当请求结束后清空,每一次请求都会重置,用于在一次请求中调用多个函数(嵌套函数)传递变量,尤其常用于登陆状态验证装饰器。
其类似于Django中的中间件,定义在请求完成过程中某个具体的时刻通用的需完成的内容,使用装饰器的形式将函数挂在钩子上,flask提供了下述四个钩子:
①before_first_request:在处理第一个请求前运行。
②before_request:在每次请求前运行。
③after_request:如果没有未处理的异常抛出,在每次请求后运行。
④teardown_request:在每次请求后运行,即使有未处理的异常抛出。其在调试模式(debug=True)不起作用。
其中①②对返回值没有要求,③④接收一个response参数(即视图函数的返回值),其可以对response进行操作,若不进行操作,则可以直接返回。
pip install Flask-Script
from flask_script import Manager
manager = Manager(app)
manage.run()
此时可以使用python xxx.py runserver/shell启动相应的服务,可以使用–help来查看其支持的命令。