Python3 - 初探 Flask-Restful

Posted 韩俊强

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Python3 - 初探 Flask-Restful相关的知识,希望对你有一定的参考价值。

文章目录

1.什么是RESTful架构:

(1)每一个URI代表一种资源;

(2)客户端和服务器之间, 传递这种资源的某种表现层;

(3)客户端通过四个HTTP动词(GET, POST, PUT, DELETE, [PATCH]), 对服务器资源进行操作, 实现"表现层状态转化"。

REST(Representational State Transfer)是一种架构风格,表述了网络中客户端于服务端的一种交互,REST本身是不实用的,关键的是如何设计它。REST架构就是为了HTTP协议设计的。RESTful web services的核心概念是管理资源。资源是由URIs来表示,客户端使用HTTP当中的’POST,GET, PUT, DELETE’等方法发送请求到服务器,改变相应的资源状态。

2.Postman

用来模拟客户端请求

3.前后端分离:

前端: app, 小程序, pc页面

后端: 没有页面, mtv: 模型模板视图, 去掉t模板

​ mv: 模型 视图

​ 模型的使用: 跟原来的用法是相同的

​ 视图: api构建视图

4. api构建视图

1. pip install flask-restful

2. 创建api对象
api = Api(app=app)
api = Api(app=蓝图对象)

3.定义类视图:
from flask_restful import Resource
class xxxApi(Resource):
	def get(self):
			pass
	
	def post(self):
			pass
	
	def put(self):
			pass
			
	def delete(self):
			pass

4.绑定
api.add.resource(xxxApi, '/user')

参照: http://www.pythondoc.com/Flask-RESTful/quickstart.html

https://flask-restful.readthedocs.io/en/latest

5.路由

原来:

@app.route('/user')
def user():              -----> 视图函数
		...
		return response对象

之前: 增加 修改 删除 查询 按钮动作 一起做
http://127.0.0.0.1:5000/user?id=1
http://127.0.0.0.1:5000/user/1

现在

restful: ---> api ---> 接口 ----> 资源 ----> url
class xxx(Resource): 			-----> 类视图
		def get(self):
			pass
		...

http://127.0.0.0.1:5000/user 一个路由做四个事情
get
post
put
delete
增加 修改 删除 查询 是通过请求方式完成的

路径产生

api.add_resource(Resource的子类, '/user')
api.add_resource(Resource的子类, '/goods')
api.add_resource(Resource的子类, '/order')

endpoint:
http://127.0.0.0.1:5000/user/1

http://127.0.0.0.1:5000/user?id=1&page=4

6.进:

1.需要定义字典, 字典的格式就是给客户端看的格式

user_fields = 
    'id': fields.Integer,
    'username': fields.String,
    'password': fields.String(attribute='private_name', default='隐私不显示'),  # 返回null
    'udatetime': fields.DateTime(dt_format='rfc822'),
    'your_phone': fields.String(attribute='phone', default='保密'), # attribute 指定返回给客户端的名字
    'icon': fields.String

客户端能看到的是: id, username, your_name, icon, udatetime

默认key的名字就是跟model中的模型属性名一致, 如果不想让前端看到命名, 则可以修改, 但是必须结合attribute='模型字段名'

自定义fileds

1.必须继承Raw

2.重写方法:

def format(self):
	return 结果
class IsDelete(fields.Raw):
    def format(self, value):
        print('------', value)
        return '删除' if value else '未删除'
user_fields = 
    'isDelete': fields.Boolean(attribute='isdelete'),
    'isDelete1': IsDelete(attribute='isdelete')

URI:

xxxList ----> 点击具体的一个获取详情 ----> 详情

定义两个user_fields,

user_fields_1 = 
    'id': fields.Integer,
    'username': fields.String(default='匿名'),
    'uri': fields.Url('single_user', absolute=True)


user_fields = 
    'id': fields.Integer,
    'username': fields.String,
    'password': fields.String(attribute='private_name', default='隐私不显示'), 
    'udatetime': fields.DateTime(dt_format='rfc822'),
    'your_phone': fields.String(attribute='phone', default='保密'),
    'icon': fields.String,
    'isDelete': fields.Boolean(attribute='isdelete'),
    'isDelete1': IsDelete(attribute='isdelete')


api.add_resource(UserSimpleResource, '/user/<int:id>', endpoint='single_user')

7.出:

return data

注意: data必须是符合json格式


	'a': 10,
	'b':[
			
				'id':1,
				'xxxlist':[
							,
				]
				
	]

如果直接返回不能有自定义的对象User, Friend…

如果有这种对象, 需要: marshal(), marchal_with()帮助进行转换

输出目的如下:


    "username": "harry",
    "nums": 5,
    "friends": [
        
            "id": 1,
            "username": "harry",
            "password": "隐私不显示",
            "udatetime": "Sat, 05 Mar 2022 17:24:43 -0000",
            "your_phone": "保密",
            "icon": null,
            "isDelete": true,
            "isDelete1": "删除"
        ,
        
            "id": 1,
            "username": "harry",
            "password": "隐私不显示",
            "udatetime": "Sat, 05 Mar 2022 17:24:43 -0000",
            "your_phone": "保密",
            "icon": null,
            "isDelete": true,
            "isDelete1": "删除"
        ,
        
            "id": 1,
            "username": "harry",
            "password": "隐私不显示",
            "udatetime": "Sat, 05 Mar 2022 17:24:43 -0000",
            "your_phone": "保密",
            "icon": null,
            "isDelete": true,
            "isDelete1": "删除"
        
    ]

user_friend_files = 
    'username': fields.String,
    'nums': fields.Integer,
    'friends': fields.List(fields.Nested(user_fields))



class UserFriendResource(Resource):
    @marshal_with(user_friend_files)
    def get(self, id):
        friends = Friend.query.filter(Friend.uid==id).all()
        user = User.query.get(id)
        friend_list = []
        for friend in friends:
            u = User.query.get(friend.uid)
            friend_list.append(u)

        data = 
            'username': user.username,
            'nums': len(friends),
            'friends': friend_list
            # 'friends': marshal(friend_list, user_fields)
        
        return data

api.add_resource(UserFriendResource, '/friend/<int:id>', endpoint='user_friend')

总结: marshal 放在局部比较灵活, marshal_with对整体控制比较好, 配合Nested可以实现套fileds

1.marchel(对象, 对象的fields格式) # 对象的field说个是指字典的输出格式

2.marchal_with()作为装饰器修饰请求方法

@marshal_with(user_friend_files)
    def get(self, id):
    		...
    		return data

函数需要参数, 参数就是最终数据输出的格式

参数: user+friend_fields, 类型是: dict类型

例如:

user_friend_files = 
    'username': fields.String,
    'nums': fields.Integer,
    'friends': fields.List(fields.Nested(user_fields))

fields.Nested(fields.String) ---> ['aa', 'bb', 'cc']
fields.Nested(user_fields) ----> user_fields是一个字典结果, 将里面的每一个对象转成
---->[user1, user2, user3]

8.跨域问题

跨域问题来源于javascript的"同源策略",即只有 协议+主机名+端口号 (如存在)相同,则允许相互访问。也就是说JavaScript只能访问和操作自己域下的资源,不能访问和操作其他域下的资源。跨域问题是针对JS和ajax的,html本身没有跨域问题。

后端: 使用第三扩展 flask-cors

9.Token令牌

在 OAuth 协议中,token 是在输入了用户名和密码之后获取的,利用这个 token 你可以拥有查看或者操作相应的资源的权限。你有这些权限,是因为服务器知道你是谁(authentication)以后赋予你的,所以 token 这个东西,其实就是你的一个『代表』,或者说完全能代表你的『通行证』。从这个概念来说,『令牌』这个翻译,真的是非常的『信雅达』啊。

Flask 实现:

import jwt
import datetime
from jwt import exceptions

JWT_SALT = 'iv%x6xo7l7_u9bf_u!9#g#m*)*=ej@bek5)(@u3kh*72+unjv='


def create_token(payload, timeout=20):
    """
    :param payload:  例如:'user_id':1,'username':'wupeiqi'用户信息
    :param timeout: token的过期时间,默认20分钟
    :return:
    """
    headers = 
        'typ': 'jwt',
        'alg': 'HS256'
    
    payload['exp'] = datetime.datetime.utcnow() + datetime.timedelta(minutes=timeout)
    result = jwt.encode(payload=payload, key=JWT_SALT, algorithm="HS256", headers=headers).decode('utf-8')
    return result


def parse_payload(token):
    """
    对token进行和发行校验并获取payload
    :param token:
    :return:
    """
    result = 'status': False, 'data': None, 'error': None
    try:
        verified_payload = jwt.decode(token, JWT_SALT, True)
        result['status'] = True
        result['data'] = verified_payload
    except exceptions.ExpiredSignatureError:
        result['error'] = 'token已失效'
    except jwt.DecodeError:
        result['error'] = 'token认证失败'
    except jwt.InvalidTokenError:
        result['error'] = '非法的token'
    return result

以上是关于Python3 - 初探 Flask-Restful的主要内容,如果未能解决你的问题,请参考以下文章

Python3 - 网络数据采集初探

Python3 - 网络数据采集初探

Python3画图系列——NetworkX初探

gitbook 准备一 [python3 WSGI 初探]

python3爬虫初探之文件保存

python3爬虫初探之requests