用flask写Restful API

4,559 阅读4分钟

Flask理解

之前一直都是用Django开发,换了新工作后,新的公司都是使用Flask+MongoDB,所以目前算初步入门了Flask。

Flask和Django的区别: 一个最明显的区别就是Django把目录结构都限制好了,开发者只需要创建相应的app,再在这个app下编写相应的models.py, views.py等。而Flask呢,仅仅只是实现了web框架最核心的功能(实际就是一个socket服务器,用户的浏览器就是一个socket客户端),有大量的第三方组件,比如ORM框架既可以选flask-sqlalchemy,也可以选flask-mongoengine,可扩展可定制,这是Flask最大的优点了, 通过这些第三方组件的组合,其实Flask也差不多是Django了。

Flask有两个核心依赖库: werkzeug和jinja。其中werkzeug负责核心的逻辑,比如路由,请求和应答的封装等。jinja是负责模板的渲染,如果开发Restful API, 后端返回给前端的只是JSON数据,所以jinja我完全没去了解。

Flask的使用

安装flask

(venv) incisordeMacBook-Pro:flask-test incisor$ pip3 install flask

来一个hello world

app.py文件

from flask import Flask

app = Flask(__name__)  # 创建一个实例

@app.route('/')
def hello_world():
    return 'hello world'


if __name__ == '__main__':
    app.run(debug=True)

通过python3 app.py启动服务器,这个时候去浏览器输入http://127.0.0.1:5000/后,就会看到hello world了。

用Flask来写一个Restful API

Django中如果要写Restful API的话,更多的是使用Django Rest Framework,当然不使用也可以,利用json.dumps()和json.loads()也行。 与Django不同的是,Flask原生就对Restful的支持已经做的很好了,JSON目前是Restful API的主流数据传输方式,Flask可以通过jsonify()将python的dict或list转成JSON。

直接上代码演示吧:

from flask import Flask, request, jsonify

app = Flask(__name__)


# 假设这是数据库存储的数据
USER_LIST = [{'id': 1, 'name': 'zws', 'age': 18}, {'id': 2, 'name': 'Tom', 'age': 19}]


@app.route('/user', methods=['GET'])
def get():
    # GET请求获取全部的数据
    return jsonify({'code': 200, 'msg': 'ok', 'data': USER_LIST})


if __name__ == '__main__':
    app.run(debug=True)

看到这,Flask已经实现了一个Restful API的GET请求,那POST, PUT, PATCH, DELETE是需要在函数里面通过request.method来判断吗?非也,Flask也是有CBV的,接下来用Flask的CBV来改善这个/user这个API。

Flask的CBV需要继承MethodView类

from flask import Flask, jsonify, request
from flask.views import MethodView

app = Flask(__name__)

USER_LIST = [{'id': 1, 'name': 'zws', 'age': 18}, {'id': 2, 'name': 'Tom', 'age': 19}]

class UserView(MethodView):

    def get(self):
        return jsonify({'code': 200, 'msg': 'ok', 'data': USER_LIST})

    def post(self):
        # get_json()把前端传来的JSON数据转成Python的dict或者list
        json_data = request.get_json()
        new_id = len(USER_LIST) + 1
        USER_LIST.append({'id': new_id, **json_data})
        return jsonify({'code': 204, 'msg': 'ok', 'data': USER_LIST[new_id-1]})


# 注册路由,name参数就是@app.route('/', methods=['GET], endpoint='')中的endpoint
# 这是视图的名字,看了源码后发现,如果不定义endpoint,默认就是当前视图函数的函数名就是endpoint
app.add_url_rule('/user', view_func=UserView.as_view(name='user'))


if __name__ == '__main__':
    app.run(debug=True)

json_data = request.get_json()这句代码需要注意,在这里出了个错误。我用postman测试POST请求时,忘记设置Content-Type了,导致request.get_json()返回None,一开始没发现是自己忘记设置Content-Type了,所以首先就直接查看了get_json()的源码:

def get_json(self, force=False, silent=False, cache=True):
    ...省略...
    if not (force or self.is_json):
        return None

self.is_json通过判断头部的Content-Type,如果设置了Content-Type: application/json,self.is_json()会返回True,那么这里会有两种处理方式: --> 请求设置Content-Type: application/json --> 请求可以不设置,而把force设置为True (force or self.is_json)其中一个返回True, 就可以了,但是为了规范,还是建议设置请求头的Content-Type,同时也可以在request.get_json()中设置force=True,做两手准备。

从以上代码可以看到利用MethodView就完全可以写Restful API了,

用flask-restful扩展库来写Restful API

flask-restful的官方文档: flask-restfule

安装

pip3 install flask-restful

修改上面的demo:

from flask import Flask, jsonify, request
from flask_restful import Api, Resource

app = Flask(__name__)
api = Api(app)


USER_LIST = [{'id': 1, 'name': 'zws', 'age': 18}, {'id': 2, 'name': 'Tom', 'age': 19}]


class UserView(Resource):

    def get(self):
        # 这里不用再自己手动调用jsonify()了
        return {'code': 200, 'msg': 'ok', 'data': USER_LIST}

    def post(self):
        json_data = request.get_json()
        new_id = len(USER_LIST) + 1
        USER_LIST.append({'id': new_id, **json_data})
        return {'code': 204, 'msg': 'ok', 'data': USER_LIST[new_id-1]}


api.add_resource(UserView, '/user')


if __name__ == '__main__':
    app.run(debug=True)

flask-restful的基本使用就是上面这些了,通过继承Resource来实现反射调用get,post这些方法。

打开Resource类,可以看到是继承了MethodView,并且重写了dispatch_request()方法,加入了dict转json的代码,这里就不分析了,因为我也只是大概了看了一下Resource的源码,以后如果详细分析了,再写篇文档吧。

到此,已经可以实现Flask开发Restful API了,经过对比,就能看出比Django轻量多少了,如果学了Django再学Flask,我感觉是分分钟就学完了。