其实网络上关于Flask的介绍文章数不胜数,所以本系列文并不是技术分享或者优化炫技,而是重个人学习的角度出发,简单谈谈自己是如何把玩Flask的。
使用Flask这种PyWeb框架的人无非三种,要么是专业的;要么写算法、模块、脚本的忽然接到个前端展示的需求;要么是写了一路java忽然发现自己要和一个叫python的乖乖对接。我是后两种的结合(疯狂暗示不专业)。
Flask有什么优点这里不做赘述,别问,问就是我是骄傲放纵的python!!!
那么网上不少的Flask教程,他们的Hello World 大概都长成这个样子:
from flask import Flask
app = Flask(__name__)
@app.route("/")
def hello():
return "Hello World!"
app.run()
其实你会发现,等你入门了,不只是Hello World ,他什么程序都长成这个样子:
① 创建 app 对象
② 配置路由以及对应的处理方法
③ run
要什么Controller、Service、Mapper、POJO,我的MVC就是一页代码!
至于页面,PyWeb的好基友Jinjia绝对首选,前后耦合的方式梦回暴力的 .jsp时代,页面代码大概长这样
Title
{{ words }}
项目结构大概长这样
但是这样的Web不是我们想要的,首先,他就算不上一个工程,你可以叫他“脚本”,但我更愿意叫他Demo,因为它会长大。想想他离一个成熟的Web还差什么?一个漂亮的项目结构、一个层次分明的架构、前后端分离的时尚方式。
一个一个来,首先想想Spring的入口类长什么样,所以app.py就应该只有一行代码
app.run()
之后的思路是:
① 利用Python的包机制,为我们的项目加一个 __init__.py来初始化我们入口py使用的app
② 单独的配置文件,在 __init__.py载入设置
③ 将路由和对应的处理方法单提出来作为Controller文件,在__init__.py装配给app
这时他的项目结构是
各个文件内容如下:
# app.py
from Normal import app
app.run()
# __init__.py
from flask import Flask
app = Flask(
__name__,
static_folder="./static",
template_folder="./templates"
)
#加载配置文件内容
app.config.from_object('Normal.setting')
# 加载 controller
from Normal.controller import index
# index.py
from Normal import app
@app.route('/')
def hello_world():
return 'Hello World!'
这回有点结构的样子,但还没有预想的好——路由就写在方法上面,能不能向VUE那样前端框架把路由和路由指向单独提出来,把一切弄得Restful一点,Flask自己提供了一个Restful的解决方案Flask-RESTful,附上地址 Flask-RESTful快速入门
但是这里,我更推荐使用一个git上的一个开源组件flask_rest_controller,这个提供一个将路由提出来的更好方案,同时提供了一个更加明确、精准的接口定义方式,更加方便的Json数据解析方式。附上地址 Flask-REST-Controller 安装方式如下:
pip install flask-rest-controller
pip install --upgrade Flask
他使用的是类似Flask-RESTful的方式,将路由与py文件里的class绑定,之后再class里定义这个路由的get、post、put等方法。与Flask-RESTful不同的:
① 每个class都继承于flask_rest_controller的Controller,并可以通过一个字典型字段 schema来定义这个class处理路由时的详细参数,样例如下:
schema = {
'GET':{ 接受的请求类型
'type':'string' 请求返回类型,可以是'object','array'
:'properties':{ 当type是object时,该object的字段信息
'id':{ 字段名
'type':'string' 字段类型'string','integer'
},
...
},
:'items':{ 当type是array时,该array的元素类型
'type':'string' 元素类型
},
},
...
}
之后对应的写schema中配置的同名的方法,如def get()。其实“同名的方法”就是重写Controller的对应get、post等方法,所以schema不配置是有默认的,默认就是这个路由可由全部的访问类型访问。特别的,还可以重写 Controller的 prepare方法和after方法。prepare方法定义正式处理(执行get或post等)之前的操作,固定return True,不然......你懂before-upload怎么卡住得吧;after方法定义正式处理(执行get或post等)之后的操作。
② 使用一个元组List来定义路由映射,格式如下:
[
(地址,对应的controller的py文件路径.类名,endpoint),
... ...
]
之后在__init__.py,通过flask_rest_controller的set_routing,把这个List(ROUTING)给app:
from flask_rest_controller import set_routing
from route import ROUTING
set_routing(app, ROUTING)
到这里我们已经拥有了一个相对漂亮的项目结构、一个相对层次分明的架构。对于前后端分离工作先给我们的app一点准备工作——跨域访问CORS,同样在__init__.py配置给app,有session需求的别忘了secret_key:
from flask_cors import CORS
app.secret_key = SECRET_KEY
CORS(app)
下次再来试试把这个改造过的Flask Web项目和VUE整合一下
最后,截止至目前我这个文章的代码样例如下
# start.py
__name__ = "RESTful"
from . import app
from .static.setting import HOST, PORT
app.run(host=HOST, port=PORT)
# __init__.py
from flask import Flask
from flask_rest_controller import set_routing
from flask_cors import CORS
from .route.route import get_routing
from .static.setting import SECRET_KEY,PROJECT_NAME
app = Flask(PROJECT_NAME)
app.config.from_object(PROJECT_NAME+'.static.setting')
app.secret_key = SECRET_KEY
CORS(app)
set_routing(app, get_routing())
# setting.py
# _*_ coding: utf-8 _*_
# ===================================================================================
# 服务器参数
# ===================================================================================
# 调试模式是否开启
DEBUG = True
# 项目名称,大小写敏感
PROJECT_NAME = 'RESTful'
# app密钥,使用 session必备
SECRET_KEY = 'NEULightBulb_ZhangJ'
# controller 的根地址 PROJECT_NAME.包名.
CONTROLLER_DIR = "RESTful.controller."
# 项目url context
CONTEXT_DIR = "/"
# 启动 HOST、PORT
HOST = 'XXX.XXX.XXX.XXX'
PORT = 8888
# route.py
from ..static.setting import CONTROLLER_DIR
from ..static.setting import CONTEXT_DIR
from ..route.route_list import ROUTING
def get_routing():
rel = []
for item in ROUTING :
rel.append((CONTEXT_DIR+item[0],CONTROLLER_DIR+item[1],item[1][item[1].rindex('.')+1:]))
return rel
# route_list.py
ROUTING = [
("heartbeat","basic.heartbeat"),
("api/submit","submit.submit"),
]
# basic.py
from flask_rest_controller import Controller
class heartbeat(Controller):
schema = {
'type': 'object',
'properties':{
'status':{
'type':'string'
}
}
}
def get(self):
return self.render_json({'status':'1'})
# submit.py
from flask_rest_controller import Controller
class submit(Controller):
schema = {
'post': {
'type': 'object',
'properties': {
'result': {
'type': 'string',
},
'code': {
'type': 'integer',
}
},
}
}
def prepare(self):
self.storage['id_card'] = self.request.json.get('id_card')
self.storage['phone'] = self.request.json.get('phone')
self.storage['address'] = self.request.json.get('address')
self.storage['select'] = self.request.json.get('select')
return True
def post(self):
print(self.storage['id_card'],
self.storage['phone'],
self.storage['address'],
self.storage['select'])
return self.render_json({"status": 0})