什么是 Flask
- python web 开发“微” 框架
- 扩展性强,精简但功能不弱
- 中文文档:https://dormousehole.readthedocs.io/en/latest/
- 英文文档:https://dormousehole.readthedocs.io/en/latest/
- Flask 简易 demo 丐中丐版:https://github.com/Yaocool/FlaskDemo
Flask 怎么用
搭建环境
略
最基本的应用
from Flask import flask
app = Flask(__name__)
@app.route('/')
def index():
return '<h1> hello world! </h1>'
if __name__ == '__main__':
app.run()
路由
Flask 中,路由是指 用户请求的 URL 与视图函数之间的映射,且 URL 后的 / 默认严格要求,即 /a 和 /a/ 代表两个路由,但是 Flask 访问 /a 时会做一次重定向访问到 /a/ 可在路由装饰器中设置 strict_slashes=False 忽略该条件
注册路由
- 路由装饰器:将一个 URL 规则绑定到一个视图函数上
# 通常使用
@app.route('/hello')
def hello():
return '<h1> hello world! </h1>'
# 或这一种,但比较麻烦,而且不够优雅,不推荐使用
app.add_url_rule('/test', view_func=test)
为路由指定 HTTP 方法
-
Flask 路由默认只支持 GET 请求,但可通过关键字 methods 指定其他一种或多种 HTTP 方法
@app.route('/login', methods=['GET', 'POST']) def hello(): return '<h1> hello world! </h1>'
匹配动态URL
同一类 URL 映射到同一个视图函数处理,比如根据不同 username 查询不同用户信息
@app.route('/user/<uname>')
def query_user(uname):
return f'hello {uname}'
URL 变量类型过滤
-
在Flask中,转换器/converter用来对从 URL 中提取的变量进行预处理,这个过程 发生在调用视图函数之前。Flask 预置了四种转换器:
- string:匹配不包含 / 的字符串,默认转换器
- path:匹配包含 / 的字符串
- int:只有当前 url 中的变量是整形值时才匹配,并将变量转换成整型
- float:只有当前 URL 变量中是浮点型时才匹配,并将变量转换成浮点型
from flask import request, Blueprint # 蓝图生成 ak = Blueprint('ak', __name__, url_prefix='/api/ak') # 蓝图注册 app.register_blueprint(ak) @ak.route('/<int:name_or_id>', methods=['DELETE']) @has_perm('ak_delete') def delete_ak(name_or_id): if name_or_id.isdigit(): id_ = int(name_or_id) akm_client.delete_ak(None, id_, zone=zone) else: akm_client.delete_ak(name_or_id, None, zone=zone) return json_ok() # /api/ak/123 OK # /api/ak/hello/123 不 OK # /api/ak/12.2 不 OK
请求 request 对象
-
封装了客户端的请求参数
from Flask import request # 获取从客户端 URL 中传输过来的查询字符串 request.args # 获取从客户端表单中提交的信息 request.form # 获取从客户端请求body中的 json 字符串 request.json # 获取客户端使用的方法 request.method # 获取从客户端请求过来的文件 request.files # 访问cookie reques.cookies
-
是一个全局对象
-
线程隔离,必须运行在当前请求中的上下文,否则报错
重定向和错误
from Flask import redirect
@app.route('/')
def index():
return '<h1> hello world! </h1>'
@app.route('/login/', methods=['POST'])
def login():
# url 跳转
return redirect('/hello/index/')
# url_for 根据别名反向解析路由
return redirect(url_for('index'))
# 使用 abort() 直接退出请求
abort(404)
print('here is never executed')
响应 make_response
视图函数的返回值会自动转换为一个响应对象。
如果返回值是一个字符串,那么会被 转换为一个包含作为响应体的字符串、一个 200 OK
代码 和一个 text/html 类型的响应对象。
如果返回值是一个字典,那么会调用 jsonify()
来产生一个响应。以下是转换的规则:
- 如果视图返回的是一个响应对象,那么就直接返回它。
- 如果返回的是一个字符串,那么根据这个字符串和缺省参数生成一个用于返回的 响应对象。
- 如果返回的是一个字典,那么调用
jsonify
创建一个响应对象。 - 如果返回的是一个元组,那么元组中的项目可以提供额外的信息。元组中必须至少 包含一个项目,且项目应当由
(response, status)
、(response, headers)
或者(response, status, headers)
组成。status
的值会重载状态代码,headers
是一个由额外头部值组成的列表 或字典。 - 如果以上都不是,那么 Flask 会假定返回值是一个有效的 WSGI 应用并把它转换为 一个响应对象。
如果想要在视图内部掌控响应对象的结果,那么可以使用 make_response()
函数。
from Flask import make_response
@app.route('/')
def index():
# 返回内容
resp = make_response('<h1> hello world </h1>')
# 返回页面
resp = make_response(render_template('xx.html'))
# 返回状态码
resp = make_response(render_template('xx.html'), 200)
# 设置 cookie
resp.set_cookie('xx', 'xx')
# 设置 header
resp.headers['X-Something'] = 'A value'
return resp
session
-
使用 session 前必须设置一个密钥,这个密钥相当于 MD5 加密的盐
from flask import Flask, session, redirect, url_for, escape, request app = Flask(__name__) app.secret_key = b'_5#y2L"F4Q8z\n\xec]/' @app.route('/') def index(): print(session['xxx']) return 'xxx'
hooks
将被装饰的函数注册到 app 中,在不同的阶段执行
-
before_first_request:在处理第一次请求前执行
-
before_request:在每次请求前执行(先于视图函数)
-
after_request:无未处理的异常抛出每次请求后执行(后于视图函数)
-
teardown_request:每次请求后执行
-
errorhandler:根据不同的错误状态码或异常
@app.errorhandler(LoginRequired) def login_redirect(e): login_url = current_app.sso_config.login_url return json_error(e, BaseErrorCode.LOGIN_REQUIRED) @app.errorhandler(500) def internal_server_error(e): return json_error(e, 'ooooops, server crashed!')
蓝图
蓝图将应用进行模块化,能够很方便的将不同的功能和路由区分开,并且易于维护,蓝图基于相同的url前缀来作区分。
from flask import request, Blueprint
# 蓝图生成
ak = Blueprint('ak', __name__, url_prefix='/api/ak')
# 蓝图注册
app.register_blueprint(ak)
@ak.route('/<name_or_id>', methods=['DELETE'])
@has_perm('ak_delete')
def delete_ak(name_or_id):
if name_or_id.isdigit():
id_ = int(name_or_id)
akm_client.delete_ak(None, id_, zone=zone)
else:
akm_client.delete_ak(name_or_id, None, zone='default')
return json_ok()
扩展
python 装饰器 与 java 注解
python 装饰器
-
和名字一样,思想是一种装饰器模式思想
-
本质是一个 Python 函数或者类,可以让使用装饰器的类或函数在不需要任何代码修改的前提下增加额外功能,返回值是一个函数或类
-
只能用于类或函数
-
与 Java 一样可实现面向切面编程,python的一种语法糖
一个简单的装饰器
def log(func): #@1
def func_dec(*args, **kwargs): #@2
r = func(*args, **kwargs) #@3
print("execute done:%s" % func.__name__)
return r
return func_dec
@log #@4
def test_dec(size, length, ky=None):
print "execute test_dec param:%s, %s, %s" % (size, length, ky)
def test():
test_dec(ky="xxx", length=3, size=1)
输出:
execute test_dec param:1, 3, xxx
execute done:test_dec
java 注解
- Java注解本质是 k-v 对,会在编译期给类增加元信息,配合反射可以实现面向切换编程
- 总的来说要比python的装饰器功能强大