Flask-Restful-Api

发布时间 2023-12-05 23:50:42作者: 一笔带过

restful

属于一种快速构建api的一种工具,和django的还是不相同的

安装
pip install flask-restful

可以和django一样进行 定义 类视图的方式
但是falskrestful中可以直接返回字典格式,它自动转换为json格式给客户端


基本的使用

from flask import Flask
from flask_restful import Resource, Api # 导入restful中的 Resource 和api

app = Flask(__name__)
api = Api(app) # 创建一个restful的api对象,将flaks的实例对象app传入

# 没有了django的序列化器的概念
# 设置路视图 继承flask_restful 中的 Resource
class HellWord(Resource):
    def get(self):
        return {'name': 'hello'} # 不需要在进行转换json格式,内部已经 帮助转换过了

    def post(self):
        return {'age': '18'}


# 使用api对象,将类视图,和路由信息进行绑定
# add_resource 帮我们调用了django的 as
api.add_resource(HellWord, '/') # hellword 类视图, / 为绑定的路径
if __name__ == '__main__':
    app.run()

127.0.0.1/ get  {'name': 'hello'}
127.0.0.1/psot {'age': '18'}


# 补充  在对象api.add_resource将 类视图和路由绑定的时候,可以进行设置一个路由的别名
api.add_resource(HellWord, '/',endpoint='HelloWorld')
通过这个参数endpoint

蓝图使用restful

from flask import Flask, Blueprint
from flask_restful import Resource, Api

app = Flask(__name__)
bp = Blueprint('bp', __name__)  # 1.创建蓝图对象

bp_api = Api(bp)  # 2.将蓝图对象传入,创建一个蓝图的api对象(绑定蓝图对象api对象)


class HellWord(Resource):
    def get(self):
        return {'name': 'hello'}



bp_api.add_resource(HellWord, '/bp/helloword')  # 3.由蓝图对象调用add_resource 绑定视图类与路径
# 蓝图注册,你不注册到flask全局对象中,蓝图的url是不会显示的
app.register_blueprint(bp)  # 4.还是需要将蓝图注册到全局的app  flask对象中的
if __name__ == '__main__':
    app.run()

restful视图使用装饰器

使用Resource 继承的 类视图的父类,中的method_decorators 属性进行使用


1.列表方式装饰器
    # 这个属性是由flask_restful框架中的 resource的属性当每次访问时,就会读取当前的 method_decorators
    # 1.当成一个列表 如果装饰器不做区分的话,使用列表,那么全部的请求方式都会加上装饰器
    # 2.当成一个字典 如果类视图中想要不同的条件加上不同的装饰器,那么就是用字典的形式


from flask import Flask
from flask_restful import Resource, Api

app = Flask(__name__)


def decorator1(func):
    def wrapper(*args, **kwargs):
        print('装饰器1')
        return func(*args, **kwargs)

    return wrapper


def decorator2(func): # 先打印
    def wrapper(*args, **kwargs):
        print('装饰器2')
        return func(*args, **kwargs)

    return wrapper


class UserInfo(Resource):
    method_decorators = [decorator1, decorator2]  # 装饰器2 先被打印
    '''    
    内部原理
    for i in method_decorators:
        func =  i(get) # 将当前的get请求的方法传入
        
        第一次遍历:
        get1  = func1(get) # 装饰器 
        第二次遍历
        get2 = func2(get1) # 将上面的装饰器对象get1传入装饰器方法2中
        
        相当于:
        @decorator2  最外层的装饰器 将下面的内容当成参数
        
        @decorator1
        def func()
        
        理解:
        decorator2(decorator1(get)) # 将下面的东西全部传入
    '''
    def get(self):
        return {'name': 'wkx'}

    def post(self):
        return {'pwd': 123}


api = Api(app)
api.add_resource(UserInfo, '/')
if __name__ == '__main__':
    app.run(debug=True)


    # 为什么先打印第二个不是第一个:
		decorator2(decorator1(get))
            --> decorator2( decorator1(get) --> wrapper内部的函数名字 内部的func指的就是get函数)
            	-->decorator2 --> 返回wrapper 内部的函数名字 其中里面的func指定就是
                		###  decorator1(get) --> wrapper内部的函数 
                    
           当 get方法被调用的使用
        		执行 decorator2 --> 返回wrapper 方法 中的 func(是decorator1 中的wrapper)
				执行后 就会还行decorator1中的wrapper 内部的func(就是get方法)
                
                
  调用装饰器  :外部的方法执行
调用被装饰的函数 :才是装饰器内部的方法被执行



####字典形式装饰 根据不同的请求装饰 不同数量的装饰器
from flask import Flask
from flask_restful import Resource, Api

app = Flask(__name__)


def decorator1(func):
    def wrapper(*args, **kwargs):
        print('装饰器1')
        return func(*args, **kwargs)

    return wrapper


def decorator2(func):
    def wrapper(*args, **kwargs):
        print('装饰器2')
        return func(*args, **kwargs)

    return wrapper


class UserInfo(Resource):
    method_decorators = {
        'get': [decorator1, decorator2], # 给get 装饰两个
        'post': [decorator2] # 给 post 装饰一个
    }

    def get(self):
        return {'name': 'wkx'}

    def post(self):
        return {'pwd': 123}


api = Api(app)
api.add_resource(UserInfo, '/')
if __name__ == '__main__':
    app.run(debug=True)

获取请求参数

原生的是request对象获取请求。
restful 提供了requestParset类 用来帮我们校验和转换请求数据的
# 简单的操作
from flask_restful.reqparse import RequestParser # 对request的进一步的封装

from flask import Flask
from flask_restful import Resource, Api
from flask_restful.reqparse import RequestParser

app = Flask(__name__)


class UserInfo(Resource):
    # http://127.0.0.1:5000/?a=10&b=20
    def get(self):
        # 作用帮我们省去了前端数据传入时的判断
        # 1. 创建对象
        rp = RequestParser()
        # 2.声明前端传入参数
        rp.add_argument('a')  # 参数名(存在几个就调用几个方法)
        rp.add_argument('b')
        # 3.执行对参数执行校验
        res = rp.parse_args()  # 可以将这个返回校验内容可以当对象和字典
        print(res)  # {'a': '10', 'b': '20'}
        # res.a 或者res.['a']

        return {'name': 'wkx'}


api = Api(app)
api.add_resource(UserInfo, '/')
if __name__ == '__main__':
    app.run(debug=True)


    
参数说明
1.required # 参数到底需不需要传递
参数默认为 False 可以不用传值
rp.add_argument('a', required=True)  报错400
# 如果设置为true,不传值的情况下,就会提示错误提示,参数必须要传


2. help 参数,定制错误的提示
rp.add_argument('a', required=True,help='参数必须传入')
# 如果这个参数不传入 的情况下,就会提示help定制的内容

3.action 如果传入的参数同名的情况下
默认 action='store' 保留出现的第一个
action = 'append' 一列表的形式追加保存同名参数的值

 rp.add_argument('a', required=True,help='参数必须传入',action='append')
 http://127.0.0.1:5000/?a=10&a=40&a=50
  {a:[10,40,50]}   

4.type 类型的制定
    1.自带
        str  会将全部的参数全部转换为字符串
        rp.add_argument('a', required=True,help='参数必须传入',type=str)
        int 传入其他类型报错,如果可以转换,那么他会转换为int
        rp.add_argument('a', required=True,help='参数必须传入',type=int) 

    在inputs模块中指定的其他类型
    from flask_restful import inputs 
    int_range :整数的返回最小1最大5 整数的返回
    rp.add_argument('a', required=True, help='参数必须传入',type=inputs.int_range(1, 5))

    natural 自然数 0...10
            rp.add_argument('a', required=True, help='参数必须传入',
                            type=inputs.natural)

    positive 正整数
            rp.add_argument('a', required=True, help='参数必须传入',
                            type=inputs.positive)

    regex 传入正则表达式    
             rp.add_argument('a', required=True, help='参数必须传入',
                            type=inputs.regex(r'\d'))
    url 传入url
            rp.add_argument('a', required=True,
                            type=inputs.url)


    自定义类型
    def mobile(mobile_str):
        '''    
        :param mobile_str:  接受被验证的参数(接受参数)
        :return: 返回验证过的数据,如果错误就抛出异常 
        '''

        if re.match(r'^1[3-9]\d{9}$',mobile_str):
            return mobile_str
        else:
            raise ValueError('{} 格式不正确'.format(mobile_str))

    rp.add_argument('a', required=True,type=mobile)
    
    
 5.指明参数传递的位置 location
        rp.add_argument('a', required=True,
                        type=int,location='form')
    
    json files cookies headers args form 等位置进行传参
    可以指明多个属性 location = [json,files]

使用序列化工具返回json格式

可以直接返回字典类型转为json格式给前端
把模型类转换字典,指定需要的内容。
工具:marshal
from flask_restful import marshal_with,marshal

marshal_with : 以视图装饰器的形式进行返回数据,对原始的marshl进行封装
marshal :直接返回数据


from flask import Flask
from flask_restful import Resource, Api, marshal_with, fields(定义类型), marshal


app = Flask(__name__)
# 指明返回数据的类型,指明以后数据会根据这个指明的类型进行转换
resouecr_fields = {
    'name': fields.String,
    'age': fields.Integer,
    'address': fields.String
}


class UserInfo(Resource):
    # @marshal_with(resouecr_fields,envelope='data)
    # def get(self):
         # 如果数据少传,就会根据少的字段赋值为null
    #     return {'name':'wkx','age':123}

    def get(self):
        # 效果和装饰器一样的
        data = {'name': 'wkx', 'age': 123}
        return marshal(data, resouecr_fields,envelope='data')  # ,需要将返回前端的参数给传入到marshal中


api = Api(app)
api.add_resource(UserInfo, '/')
if __name__ == '__main__':
    app.run(debug=True)
    
    
# envelope的参数意思就是将返回的参数内嵌到一个字典中
{
    "data": {
            "name": "wkx",
            "age": 123,
            "address": null
            }
}	

定制返回的json数据

from flask import make_response, current_app
from flask_restful.utils import PY3
from json import dumps


# 这个是restful中api中的提供的一个带参数的装饰器,允许定制返回数据的呈现格式
# 需要经过这里转变为json返回给前端
@api.representations('application/json')
def handle_json(data, code, headers):
    '''
    :param data: 接受视图的返回字典数据(需要返回前端)
    :param code: 想返回的状态码
    :param headers: 返回的表头
    :return: 返回给前端的数据
    '''
    # 如果传入的数据,没有带message 就给它包裹一层
    if 'message' not in data:
        data = {
            'message': 'OK',
            'data': data
        }
    # 原代码不动
    settings = current_app.config.get('RESTFUL_JSON', {})
    if current_app.debug:
        settings.setdefault('indent', 4)
        settings.setdefault('sort_keys', not PY3)
    dumped = dumps(data, **settings) + "\n"
    resp = make_response(dumped, code)
    resp.headers.extend(headers or {})
    return resp


调用原代码 进行原始的封装,该原来的原代码