第七课 Flask-Restful的使用

第七课 Flask-Restful的使用

tags:

  • Flask
  • 2019千锋教育

categories:

  • flask-Restful
  • 返回值序列化
  • RequestParser对象

第一节 Flask-Restful介绍安装

  1. 官网:https://flask-restful.readthedocs.io/en/latest/index.html

  2. 安装:pip install Flask-RESTful -i https://pypi.douban.com/simple

  3. restful api是用于在前端与后台进行通信的一套规范。使用这个规范可以让前后端开发变得更加轻松。以下将讨论这套规范的一些设计细节

  4. 协议:采用http或者https协议。

  5. 数据传输格式: 数据之间传输的格式应该都使用json,而不使用xml。

  6. url链接:url链接中,不能有动词,只能有名词。并且对于一些名词,如果出现复数,那么应该在后面加s。比如:获取文章列表,应该使用/articles/,而不应该使用/get_article/

  7. HTTP请求的方法:

    • GET:从服务器上获取资源。
    • POST:在服务器上新创建一个资源。
    • PUT:在服务器上更新资源。(客户端提供所有改变后的数据)
    • PATCH:在服务器上更新资源。(客户端只提供需要改变的属性)
    • DELETE:从服务器上删除资源。
  8. 示例如下:

    • GET /users/:获取所有用户。
    • POST /user/:新建一个用户。
    • GET /user/id/:根据id获取一个用户。
    • PUT /user/id/:更新某个id的用户的信息(需要提供用户的所有信息)。
    • PATCH /user/id/:更新某个id的用户信息(只需要提供需要改变的信息)。
    • DELETE /user/id/:删除一个用户。
  9. 写一个Resource资源apis.py

# apis.py
from flask_restful import Api, Resource


api = Api()
def init_ api (app):
	api.init_app(app)
	
	
class HelloResource(Resource):
	def get(self):
		return {"msg": "hello api get"}
		
	def post(self):
		return {"msg": "hello api post"}

# 注册HelloResource 通过
api.add_resource(HelloResource, '/hello/')
  1. 这里去掉了之前views的方式注册路由。通过127.0.0.1:5000/hello/,访问资源。
# __init__.py
from App.apis import init_api

# 只要路由相关的 都写在__init__.py中 不要卸载ext中
init_api(app=app)
  1. 把上面的apis.py 变成包的形式。用来写不同种类的接口。
  2. 除了Flask-Restful可以用来实现这个,flask还有其他的包也可以用来实现Restful接口。
    • Flask-Restless https://restless.readthedocs.io/en/latest/ (测试版 bug多)
    • Flask-REST-JSONAPI https://flask-rest-jsonapi.readthedocs.io/en/latest/

第二节 Flask-Restful返回数据序列化

  1. 序列化: 直接调用marshal函数或者通过marshal_with装饰。它装饰内部也是调用marshal函数
    • 直接marshal函数 “data”: marshal(goods, goods_fields)
    • @marshal_with(goods_fields) 可以直接返回goods
    • 想要返回data,data中嵌套goods: 写一个single_goods_fields如下。使用装饰器@marshal_with(single_goods_fields)
  2. goods_fields和single_goods_fields 实际上就是我们需要返回数据对象序列化的模板
  3. 模版中多个没有的字段 不会报错 返回null 比如: “hh”: fields.String
  4. 以格式的模板为主
    • 如果格式和数据完全对应,数据就是预期格式
    • 如果格式比数据中的字段多,程序依然正常运行,不存在的字段是默认值"desc": fields.String(default=‘success’),
    • 如果格式比数据中的字段少,程序正常执行,少的字段不会显示
  5. 格式和数据的映射
    • 格式中的字段名和数据中的名需要一致
    • 不一致可以起别名解决:“name”: fields.String(attribute=‘g_name’)
    • 返回URL:‘uri’: fields.Url(‘single_goods’, absolute=True) absolute 绝对路径
      • 需要加上endpoint名称:api.add_resource(GoodsResource, “/goods/int:id/”, endpoint=“single_goods”)
  6. 模板中的字段fields
    • Raw
      • format
      • output
      • 调用
        • 将数据传递进格式化工具的时候,先获取值output
        • 再对值进行格式化 format
    • String
      • 继承Raw
      • 将value进行格式化
      • 转换成兼容格式的text
    • Interger
      • 继承自Raw
      • 重写了初始化,将default设置为0
      • 重写格式化 直接将value转换成int
    • Boolean
      • 继承自Raw
      • 重写格式化
      • 重写格式化,直接将value转换成 bool
    • Nested
      • 继承自Raw
      • 重写output
      • 进行marshal
    • List
      • 继承自Raw
      • 重写output
        • 判断你的类型
        • 对不同的类型进行不同的处理
          • dict 直接进行处理
          • list 迭代处理
      • 重写format
        • 进行格式化
# goods_api.py
from flask import request
from flask_restful import Resource, fields, marshal_with, marshal, abort, reqparse

from App.models import Goods

goods_fields = {
    "id": fields.Integer,
    "name": fields.String(attribute='g_name'),
    "g_price": fields.Float,
    'uri': fields.Url('single_goods', absolute=True)
}

single_goods_fields = {
    "data": fields.Nested(goods_fields),
    "status": fields.Integer,
    "msg": fields.String,
}

multi_goods_fields = {
    "status": fields.Integer,
    "msg": fields.String,
    "data": fields.List(fields.Nested(goods_fields)),
    "desc": fields.String(default='success'),
    "number":fields.Integer
}


parser = reqparse.RequestParser()
parser.add_argument("g_name", type=str, required=True, help="please input g_name")
parser.add_argument("g_price", type=float, help="please input number")
parser.add_argument("mu", action="append")
parser.add_argument('rname', dest="name")
parser.add_argument("OUTFOX_SEARCH_USER_ID_NCOO", dest="lo", action="append", location=["cookies", "args"])
parser.add_argument("User-Agent",dest="ua", location="headers")


class GoodsListResource(Resource):

    # @marshal_with(multi_goods_fields)
    def get(self):
        args = parser.parse_args()
        print(args.get("lo"))
        print(args.get("ua"))
        goods_list = Goods.query.all()

        data = {
            "status": 200,
            "msg": "ok",
            "data": goods_list,
            'desc': "Get Ok"
        }

        return marshal(data, multi_goods_fields)

    @marshal_with(single_goods_fields)
    def post(self):
        # g_name = request.form.get('g_name')
        # g_price = request.form.get('g_price')
        args = parser.parse_args()
        g_name = args.get('g_name')
        g_price = args.get('g_price')
        print(args.get('mu'))
        print(args.get('name'))
        goods = Goods()
        goods.g_name = g_name
        goods.g_price = g_price
        if not goods.save():
            abort(400)
        """
            JSON
                Response
                
            格式
                单个对象
                
                {
                    "status": 200,
                    "msg"   : "ok",
                    "data"  :{
                        "property": "value",
                        "property": "value",
                        "property": "value",
                    }
                    
                }
                
                多个对象,列表对象
                {
                    "status": 200,
                    "msg"   : "ok",
                    "data"  : [
                        {
                                "property": "value",
                                "property": "value",
                                "property": "value"
                        },
                        {
                                "property": "value",
                                "property": "value",
                                "property": "value"
                        },
                        {
                                "property": "value",
                                "property": "value",
                                "property": "value"
                        },
                        
                    ]
                
                }
        """

        data = {
            "msg": "create success",
            "status": 201,
            # "data": marshal(goods, goods_fields)
            "data": goods
        }

        return data


class GoodsResource(Resource):

    @marshal_with(single_goods_fields)
    def get(self, id):
        goods = Goods.query.get(id)
        data = {
            "status": 200,
            "msg": "ok",
            "data": goods
        }
        return data

    def delete(self, id):
        goods = Goods.query.get(id)
        if not goods:
            # abort(404)
            abort(404, message="goods doesn't exist", msg="fail")
        if not goods.delete():
            abort(400)
        data = {
            "msg": "delete success",
            "status": 204
        }
        return data

    def put(self, id):
        goods = Goods.query.get(id)
        if not goods:
            abort(404)
        g_price = request.form.get('g_price')
        g_name = request.form.get('g_name')
        goods.g_price = g_price
        goods.g_name = g_name
        if not goods.save():
            abort(400)

        data = {
            "msg": "put ok",
            "status": 201,
            "data": goods
        }
        return marshal(data, single_goods_fields)

    @marshal_with(single_goods_fields)
    def patch(self, id):
        goods = Goods.query.get(id)
        if not goods:
            abort(404)
        g_price = request.form.get('g_price')
        g_name = request.form.get('g_name')
        goods.g_price = g_price or goods.g_price
        goods.g_name = g_name or goods.g_name
        if not goods.save():
            abort(400)

        data = {
            "msg": "put ok",
            "status": 201,
            "data": goods
        }

        return data
#models.py
from App.ext import db


class BaseModel(db.Model):
    __abstract__ = True
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)

    def save(self):
        try:
            db.session.add(self)
            db.session.commit()
            return True
        except Exception as e:
            print(e)
            return False

    def delete(self):
        try:
            db.session.delete(self)
            db.session.commit()
            return True
        except Exception as e:
            print(e)
            return False


class Goods(BaseModel):
    g_name = db.Column(db.String(64))
    g_price = db.Column(db.Float, default=0)

第三节 Flask-Restful RequestParser对象

  1. RequestParser使用过程
    • 先定义一个RequestParser对象
    • 向对象中添加字段
    • 从对象中获取字段
  2. 对象在添加参数的时候,可以实现数据预校验
    • 参数是否必须
    • 数据的类型
    • 还可以设置错误提示
    • 接收多个值 action=“append”
    • 也可以在接收的时候指定别名
    • location 可以指定参数的来源
parser = reqparse.RequestParser()
# 可以帮我们校验前端数据 required=True
parser.add_argument("g_name", type=str, required=True, help="please input g_name")
# 校验数据类型
parser.add_argument("g_price", type=float, help="please input number")
# 接收多个值 比如复选框
parser.add_argument("mu", action="append")
# 前端传rname 后台接收name
parser.add_argument('rname', dest="name")
# 指定数据来源为 cookies或者args 可以指定一个或多个。 
# 追加说明 拿多个值放到列表中
parser.add_argument("OUTFOX_SEARCH_USER_ID_NCOO", dest="lo", action="append", location=["cookies", "args"])
parser.add_argument("User-Agent",dest="ua", location="headers")


# 获取参数
args = parser.parse_args()
g_name = args.get('g_name')
g_price = args.get('g_price')
# 返会多个值的列表
print(args.get('mu'))
print(args.get('name'))

第四节 爬虫与反爬虫

  1. 基于IP频率反爬
    • 客户端使用代理服务器
  2. 基于UA
    • 使用UA池
  3. 基于Cookie或用户反爬
    • Cookie池
    • 登陆大量账号,存储cookie
发布了61 篇原创文章 · 获赞 8 · 访问量 2797

猜你喜欢

转载自blog.csdn.net/aa18855953229/article/details/105330006