Flask-Restful

Flask 和 Flask-Restful 关系

Flask-RESTful是一个 Flask 扩展,它添加了快速构建 REST APIs 的支持

使用教程

安装

python 复制代码
pip install flask-restful

Flask转化成Flask-Restful

  • 原本的Flask代码
python 复制代码
from flask import Flask, jsonify

app = Flask(__name__)

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

if __name__ == '__main__':
    app.run(debug=True)
  • 转化后的代码
python 复制代码
from flask import Flask
from flask_restful import Resource, Api

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

class HelloWorld(Resource):
    def get(self):
        return {'hello': 'world'}

api.add_resource(HelloWorld, '/')

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

这段代码使用了 Flask 的 jsonify 函数来保证将 Python 的字典转换为 JSON 响应。在这个简单的例子中,使用 Flask-RESTful 与仅使用 Flask 的差别不大,因为都是在处理一个简单的 GET 请求。然而,Flask-RESTful 的真正优势在于处理更复杂的场景和多个端点,以及更细粒度的控制,如请求解析和数据序列化

Flask-RESTful视图

通过endpoint参数为路由起名

endpoint是用来给url_for反转url的时候指定的,

如果不写endpoit,那么就会使用视图的名字的小写来作为endpoint

python 复制代码
from flask import Flask
from flask_restful import Resource, Api

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


class HelloWorldResource(Resource):
    def get(self, name="123"):
        print(name)
        return {'hello': 'world'}

    def post(self):
        return {'msg': 'post hello world'}


# api.add_resource(HelloWorldResource, '/')
api.add_resource(HelloWorldResource, '/', '/<name>', endpoint='helloworld')

# 此处启动对于1.0之后的Flask可有可无
if __name__ == '__main__':
    app.run(debug=True)
    
# endpoint是用来给url_for反转url的时候指定的,
# 如果不写endpoit,那么就会使用视图的名字的小写来作为endpoint
# add_resource的第二个参数时访问这个视图函数的url,
# 这个url可以跟之前的route一样,传递参数,并且可以传递多个url.
蓝图中使用
python 复制代码
from flask import Flask, Blueprint
from flask_restful import Api, Resource

app = Flask(__name__)

user_bp = Blueprint('user', __name__)

user_api = Api(user_bp)

class UserProfileResource(Resource):
    def get(self):
        return {'msg': 'get user profile'}

user_api.add_resource(UserProfileResource, '/users/profile')

app.register_blueprint(user_bp)
装饰器

使用method_decorators添加装饰器

  • 为类视图中的所有方法添加装饰器
python 复制代码
def decorator1(func):
    def wrapper(*args, **kwargs):
        print('decorator1')
        return func(*args, **kwargs)
    return wrapper


def decorator2(func):
    def wrapper(*args, **kwargs):
        print('decorator2')
        return func(*args, **kwargs)
    return wrapper


class DemoResource(Resource):
    method_decorators = [decorator1, decorator2]

    def get(self):
        return {'msg': 'get view'}

    def post(self):
        return {'msg': 'post view'}
  • 为类视图中不同的方法添加不同的装饰器
python 复制代码
class DemoResource(Resource):
    method_decorators = {
        'get': [decorator1, decorator2],
        'post': [decorator1]
    }

    # 使用了decorator1 decorator2两个装饰器
    def get(self):
        return {'msg': 'get view'}

    # 使用了decorator1 装饰器
    def post(self):
        return {'msg': 'post view'}

    # 未使用装饰器
    def put(self):
        return {'msg': 'put view'}

关于请求处理

Flask-RESTful 提供了RequestParser类 Argument Parsing,用来帮助我们检验和转换请求数据。

下面是一个使用 reqparse 的简单例子:

首先,你需要从 flask_restful 导入 reqparse

python 复制代码
from flask_restful import reqparse

然后,创建一个 RequestParser 的实例,并通过 add_argument 方法添加你想要验证的参数:

python 复制代码
from flask_restful import reqparse

parser = reqparse.RequestParser()
parser.add_argument('rate', type=int, help='Rate cannot be converted', location='args')
parser.add_argument('name')
args = parser.parse_args()

使用步骤:

python 复制代码
1. 创建RequestParser对象
2. 向RequestParser对象中添加需要检验或转换的参数声明
3. 使用parse_args()方法启动检验处理
4. 检验之后从检验结果中获取参数时可按照字典操作或对象属性操作
       args.rate
       或
       args['rate']
required
python 复制代码
描述请求是否一定要携带对应参数,默认值为False

- True 强制要求携带
  若未携带,则校验失败,向客户端返回错误信息,状态码400
- False 不强制要求携带
  若不强制携带,在客户端请求未携带参数时,取出值为None

    class DemoResource(Resource):
        def get(self):
            rp = RequestParser()
            rp.add_argument('a', required=False)
            args = rp.parse_args()
            return {'msg': 'data={}'.format(args.a)}
help
python 复制代码
参数检验错误时返回的错误描述信息
rp.add_argument('a', required=True, help='missing a param')
action
python 复制代码
描述对于请求参数中出现多个同名参数时的处理方式

- action='store' 保留出现的第一个, 默认
- action='append' 以列表追加保存所有同名参数的值

rp.add_argument('a', required=True, help='missing a param', action='append')
type
python 复制代码
- 标准类型
      rp.add_argument('a', type=int, required=True, help='missing a param', action='append')
      
- Flask-RESTful提供
  检验类型方法在flask_restful.inputs模块中

  - url
  - regex(指定正则表达式)
        from flask_restful import inputs
        rp.add_argument('a', type=inputs.regex(r'^\d{2}&'))
        
  - natural 自然数0、1、2、3...
  - positive 正整数 1、2、3...
  - int_range(low ,high) 整数范围
        rp.add_argument('a', type=inputs.int_range(1, 10))
        
  - boolean
自定义
python 复制代码
def mobile(mobile_str):
    """
    检验手机号格式
    :param mobile_str: str 被检验字符串
    :return: mobile_str
    """
    if re.match(r'^1[3-9]\d{9}$', mobile_str):
        return mobile_str
    else:
        raise ValueError('{} is not a valid mobile'.format(mobile_str))

rp.add_argument('a', type=mobile)
location
python 复制代码
描述参数应该在请求数据中出现的位置
# Look only in the POST body
parser.add_argument('name', type=int, location='form')

# Look only in the querystring
parser.add_argument('PageSize', type=int, location='args')

# From the request headers
parser.add_argument('User-Agent', location='headers')

# From http cookies
parser.add_argument('session_id', location='cookies')

# From json
parser.add_argument('user_id', location='json')

# From file uploads
parser.add_argument('picture', location='files')

# 也可指明多个位置
parser.add_argument('text', location=['headers', 'json'])
choices
python 复制代码
parse.add_argument('gender', type=str,choices=['1','2'],help='没有可选项')
trim
python 复制代码
parse.add_argument('username',trim=True, type=str,default='张三', help='用户名验证错误'

关于响应处理

fields 和 marshal_with模块

reqparse 和 fields 模块以及marshal_with 装饰器在 Flask-RESTful 中分别用于处理不同的任务。reqparse 主要用于处理和验证输入数据(即请求数据),而 fields 模块和 marshal_with() 装饰器用于格式化和输出数据(即响应数据)。让我们详细探讨一下它们各自的作用:

Flask-RESTful 的 fields 模块和 marshal_with() 装饰器用于定义和格式化返回的 JSON 数据结构。当你的 API 需要返回结构化的响应数据时,这些工具可以帮助你确保响应体的格式是正确的,即使你的内部数据结构是复杂的对象。

序列化数据

Flask-RESTful 提供了marshal工具,用来帮助我们将数据序列化为特定格式的字典数据,以便作为视图的返回值。

python 复制代码
from flask_restful import Resource, fields, marshal_with

resource_fields = {
    'name': fields.String,
    'address': fields.String,
    'user_id': fields.Integer
}

class Todo(Resource):
    @marshal_with(resource_fields, envelope='resource')
    def get(self, **kwargs):
        return db_get_todo()

也可以不使用装饰器的方式

python 复制代码
class Todo(Resource):
    def get(self, **kwargs):
        data = db_get_todo()
        return marshal(data, resource_fields)

示例

python 复制代码
# 用来模拟要返回的数据对象的类
class User(object):
    def __init__(self, user_id, name, age):
        self.user_id = user_id
        self.name = name
        self.age = age

resoure_fields = {
        'user_id': fields.Integer,
        'name': fields.String
    }

class Demo1Resource(Resource):
    @marshal_with(resoure_fields, envelope='data1')
    def get(self):
        user = User(1, 'itcast', 12)
        return user

class Demo2Resource(Resource):
    def get(self):
        user = User(1, 'itcast', 12)
        return marshal(user, resoure_fields, envelope='data2')

定制返回的JSON格式

需求: 想要接口返回的JSON数据具有如下统一的格式

python 复制代码
{"message": "描述信息", "data": {要返回的具体数据}}

解决:Flask-RESTful的Api对象提供了一个representation的装饰器,允许定制返回数据的呈现格式

python 复制代码
api = Api(app)

@api.representation('application/json')
def handle_json(data, code, headers):
    # TODO 此处添加自定义处理
    return resp

Flask-RESTful原始对于json的格式处理方式如下:

代码出处:flask_restful.representations.json

python 复制代码
from flask import make_response, current_app
from flask_restful.utils import PY3
from json import dumps


def output_json(data, code, headers=None):
    """Makes a Flask response with a JSON encoded body"""

    settings = current_app.config.get('RESTFUL_JSON', {})

    # If we're in debug mode, and the indent is not set, we set it to a
    # reasonable value here.  Note that this won't override any existing value
    # that was set.  We also set the "sort_keys" value.
    if current_app.debug:
        settings.setdefault('indent', 4)
        settings.setdefault('sort_keys', not PY3)

    # always end the json dumps with a new line
    # see https://github.com/mitsuhiko/flask/pull/1262
    dumped = dumps(data, **settings) + "\n"

    resp = make_response(dumped, code)
    resp.headers.extend(headers or {})
    return resp

为满足需求,做如下改动即可

python 复制代码
@api.representation('application/json')
def output_json(data, code, headers=None):
    """Makes a Flask response with a JSON encoded body"""

# 此处为自己添加***************
if 'message' not in data:
    data = {
        'message': 'OK',
        'data': data
    }
# **************************

settings = current_app.config.get('RESTFUL_JSON', {})

# If we're in debug mode, and the indent is not set, we set it to a
# reasonable value here.  Note that this won't override any existing value
# that was set.  We also set the "sort_keys" value.
if current_app.debug:
    settings.setdefault('indent', 4)
    settings.setdefault('sort_keys', not PY3)

# always end the json dumps with a new line
# see https://github.com/mitsuhiko/flask/pull/1262
dumped = dumps(data, **settings) + "\n"

resp = make_response(dumped, code)
resp.headers.extend(headers or {})
return resp
相关推荐
我不会编程5554 小时前
Python Cookbook-2.24 在 Mac OSX平台上统计PDF文档的页数
开发语言·python·pdf
胡歌15 小时前
final 关键字在不同上下文中的用法及其名称
开发语言·jvm·python
程序员张小厨6 小时前
【0005】Python变量详解
开发语言·python
Hacker_Oldv7 小时前
Python 爬虫与网络安全有什么关系
爬虫·python·web安全
深蓝海拓7 小时前
PySide(PyQT)重新定义contextMenuEvent()实现鼠标右键弹出菜单
开发语言·python·pyqt
数据攻城小狮子9 小时前
深入剖析 OpenCV:全面掌握基础操作、图像处理算法与特征匹配
图像处理·python·opencv·算法·计算机视觉
ONE_PUNCH_Ge9 小时前
Python 爬虫 – BeautifulSoup
python
L_cl9 小时前
【Python 数据结构 1.零基础复习】
数据结构·python
Monkey_Jun9 小时前
《Python百练成仙》31-40章(不定时更新)
开发语言·python