Flask Restful
1.安装
在
Flask
中,为了写出更优雅的API
,提供了一个插件FLask Restful
.$ pip install flask_restful
官网
2.基本应用
一个简单的
API
类似如下:#!/usr/bin/env python
# coding=utf-8
from flask import Flask
from flask_restful import Resource,Api
app = Flask(__name__)
# 1.Api绑定app
api = Api(app)
# 定义一个GET/Post方法
class HelloWorld(Resource):
def get(self):
return {'hello':'world'}
# 注册URL 资源
api.add_resource(HelloWorld,'/api/hello/')
@app.route('/')
def hello_world():
return 'Hello World!'
if __name__ == '__main__':
app.run(debug=True)测试联通性:
❯ curl http://127.0.0.1:5000/api/hello/
{
"hello": "world"
}
3.Resource routing
资源路由
Flask_Restful
提供的最主要的基础就是资源Resource
类.它是构建在Flask可拔插视图
之上的,利用它可以很容易的访问多个HTTP
方法.>>> from flask_restful import Resource
>>> help(Resource)
class Resource(MethodView):
# Resource继承自MethodView,这意味者它可以重写 get/post等方法from flask import Flask,request
from flask_restful import Resource,Api
app = Flask(__name__)
# 1. Api初始化app
api = Api(app)
todos = {}
# 2.重写 Get/Post方法
class TodoSimple(Resource):
def get(self,todo_id):
'''重写 get 方法'''
return {todo_id:todos[todo_id]}
def post(self,todo_id):
'''重写 post 方法'''
todos[todo_id] = request.form.get('data')
return {todo_id:todos[todo_id]}
# 3.注册资源
# 访问URL的变量部分,可以使用 <converter:variable_name>
# 此部分可以写成
# api.add_resource(TodoSimple,'/api/todos/<todo_id>')
api.add_resource(TodoSimple,'/api/todos/<string:todo_id>')
if __name__ == '__main__':
app.run(debug=True)访问:
❯ curl http://127.0.0.1:5000/api/todos/todo1 -d "data=test" -X POST
{
"todo1": "test"
}
❯ curl http://127.0.0.1:5000/api/todos/todo1
{
"todo1": "test"
}
❯ curl http://127.0.0.1:5000/api/todos/todo2 -d "data=test2" -X POST
{
"todo2": "test2"
}
❯ curl http://127.0.0.1:5000/api/todos/todo2
{
"todo2": "test2"
}
add_resource
,可以添加url
中的变量参数,以及多个url
.
4.endpoint
可以在
API
中指定多个URL
,他们指定在Api.add_resource()
方法中.每个URL
都能访问Resource
.api.add_resource(HelloWorld, '/','/hello')
# 127.0.0.1:5000
# 127.0.0.1:5000/hello 都可以访问到 HelloWold类中定义的内容还可以为资源方法指定
endpoint
api.add_resource(TodoSimple,'/api/todos/<string:todo_id>',endpoint='todos')
# 1. Api初始化app
api = Api(app)
todos = {}
# 2.重写 Get/Post方法
class TodoSimple(Resource):
def get(self,todo_id=None):
'''重写 get 方法'''
return {todo_id:todos[todo_id]}
def post(self,todo_id=None):
'''重写 post 方法'''
todos[todo_id] = request.form.get('data')
return {todo_id:todos[todo_id]}
# 3.注册资源
# 访问URL的变量部分,可以使用 <converter:variable_name>
# 此部分可以写成
# api.add_resource(TodoSimple,'/api/todos/<todo_id>')
api.add_resource(TodoSimple,'/api/todos/<string:todo_id>',endpoint='todos')
with app.test_request_context():
print(url_for('todos',todo_id='test3'))
if __name__ == '__main__':
app.run(debug=True)
endpoint
是用来给url_for
反转的时候指定的.如果不写endpoint
,那么将会使用视图的名字的小写作为endpoint
.以上如果不写
endpoint
with app.test_request_context():
print(url_for('todosimple',todo_id='test3'))
5.Argument Parsing
参数解析
Flask_Restful
提供了简单的表单验证功能,类似与WTForms
,但是非常的简陋.它使用了一个argparse
库.from flask_restful import reqparse
parse = reqparse.RequestParser()
parse.add_argument('rate', type=int, help='this is a test')
args = parse.parse_args() # 返回一个字典对象
parse.add_argument()
常用参数有
default='value'
:指定默认值,如果前端没有传递值,就使用默认值.required=True
:要求前端必须传递值,默认为False
.type=str
:指定数据类型,要求前端必须传递规定的数据类型,可以使用python
字典的数据类型,也可以指定flask_restful.inputs
模块下的值,比如:
falsk_restful.inputs.url
:验证URL
falsk_restful.inputs.boolean
:验证布尔值,可以是True/False
或01
falsk_restful.inputs.date
:验证日期格式是YYYY-mm-dd
falsk_restful.inputs.reqex()
:验证正则表达式choices=[]
:指定一个列表,前端的值必须是列表中的值.help='xxx
‘: 指定出错的一个帮助信息.trim=True
: 指定去除前端返回值的空格.默认是False
.from flask import Flask,request
from flask_restful import Api,Resource,reqparse,inputs
app = Flask(__name__)
app.config.update({'DEBUG':True})
# 1.Api绑定app
api = Api(app)
# 2.重载get/post 方法
class RegiseterView(Resource):
def get(self):
return {'login':'???'}
def post(self):
'''验证的输入'''
parse = reqparse.RequestParser()
# 去除前端返回值的空格
parse.add_argument('username',type=str,help='用户名不正确',trim=True)
parse.add_argument('password',type=str,help='密码不正确',trim=True)
# 使用type=int,使用默认值
parse.add_argument('age',type=int,help='年龄必须是整数',trim=True,default=18)
# 使用inputs.date 数据类型
parse.add_argument('birthday',type=inputs.date,help='日期不正确',trim=True)
# 使用inputs.regex
parse.add_argument('phone',type=inputs.regex(r'1[3789]d{9}'),help='手机号码不正确',trim=True)
# 使用inputs.boolean
parse.add_argument('gender',type=str,choices=['male','female'],help='性别不正确',trim=True)
# 打印
args = parse.parse_args()
print(args)
return args
# 3.注册路由
api.add_resource(RegiseterView,'/api/register/',endpoint='register')
if __name__=='__main__':
app.run()访问并得到
❯ curl http://127.0.0.1:5000/api/register/ -d "username=Jack&password=aaa&age=19&phone=18618609966&gender=male" -X POST
{
"username": "Jack",
"password": "aaa",
"age": 19,
"birthday": null,
"phone": "18618609966",
"gender": "male"
}
6.格式化字段
Flask_Restful
提供了一种简单的方法来控制在HTTP Response
中实际呈现的数据.可以简单的返回一个字典类型的数据,也可以使用flask_restful.fields
模块,这个模块允许在资源中使用所需要的任何对象(ORM
自定义类等等),它还可以格式化或过滤HTTP Response
,而不必担心暴露内部数据结构.
1.基本用法
可以定义一个
fields
的OrderedDict
字典,键指向属性名称或要呈现在对象上的键,值是格式化并返回该字段的类.类似如下:from flask_restful import Resource,fields,marshal_with,Api
from flask import Flask
from datetime import datetime
# pytz是一个时区的datetime object
import pytz
app = Flask(__name__)
# 1.Api绑定app
api = Api(app)
class Register:
def __init__(self,name):
self.name = name
self.date = datetime.now(tz=pytz.timezone('Asia/Shanghai'))
# 2.重载Get/Post方法
class Todo(Resource):
resource_fields = {
'name':fields.String,
'date': fields.DateTime(dt_format='rfc822')
}
@marshal_with(resource_fields)
def get(self,name):
print(name)
return Register(name),200 # 可以返回状态码
# 3.注册路由/资源
api.add_resource(Todo,'/api/todo/<name>/',endpoint='todo')
if __name__ == '__main__':
app.run(debug=True)访问并得到:
❯ curl http://127.0.0.1:5000/api/todo/Jack/
{
"name": "Jack",
"date": "Wed, 11 Dec 2015 15:07:36 -0000"
}
@marshel_with
是一个装饰器,能真正接受对象,并过滤字段.
2.重命名属性
出于隐藏后台数据,保证安全的角度考虑,可以使用
attribute
配置面向公众的字段.比如resource_fields={
'name' = fields.String(attribute='true_name')
}
# 任何可调用的函数,比如 lambda 也可以指定 attribute
resource_fields={
'name' = fields.String(attribute=lambda x:x.true_name)
}
# 也可以指定嵌套属性
resource_fields = {
'name': fields.String(attribute='people_list.0.person_dictionary.name'),
'address': fields.String,
}
3.默认值
可以指定默认值,这样就不会返回
None
resource_fields = {
'name':fields.String(default='any')
}
4.自定义字段和值
如果需要自定义格式,可以继承自
fields.Raw
类并重载format
方法.比如:class UrgentItem(fields.Raw):
def format(self, value):
return "Urgent" if value & 0x01 else "Normal"
class UnreadItem(fields.Raw):
def format(self, value):
return "Unread" if value & 0x02 else "Read"
resource_fields = {
'name': fields.String,
'priority': UrgentItem(attribute='flags'),
'status': UnreadItem(attribute='flags'),
}
5.fields.Url
fields.Url
:为请求的资源综合一个URL
.类似如下from flask_restful import Resource,fields,marshal_with,Api
from flask import Flask
from datetime import datetime
# pytz是一个时区的datetime object
import pytz
app = Flask(__name__)
# 1.Api绑定app
api = Api(app)
class Register:
def __init__(self,name):
self.name = name
self.date = datetime.now(tz=pytz.timezone('Asia/Shanghai'))
# 2.重载Get/Post方法
class Todo(Resource):
resource_fields = {
'name':fields.String,
'date': fields.DateTime(dt_format='rfc822'),
# 返回一个url 相对路径
'uri': fields.Url('todo'),
# 返回一个url 绝对路径
'uri_absolute': fields.Url('todo',absolute=True),
# 返回一个url http绝对路径
'https_uri':fields.Url('todo',absolute=True,scheme='https')
}
@marshal_with(resource_fields)
def get(self,name):
print(name)
return Register(name)
# 3.注册路由/资源
api.add_resource(Todo,'/api/todo/<name>/',endpoint='todo')
if __name__ == '__main__':
app.run(debug=True)访问:
❯ curl http://127.0.0.1:5000/api/todo/Jack/
{
"name": "Jack",
"date": "Thu, 12 Dec 2019 11:14:05 -0000",
"uri": "/api/todo/Jack/",
"uri_absolute": "http://127.0.0.1:5000/api/todo/Jack/",
"https_uri": "https://127.0.0.1:5000/api/todo/Jack/"
}
6.复杂结构
引入2个方法:
flask_restful.marshal(data,fields,envelope=None)
:把dictlist
数据类型转换为OrderedDict
数据类型,用于过滤数据.# data:实际的对象
# fields: 需要过滤的数据类型
# envelope: 类似别名
# 原始数据,需要过滤的数据
>>> data = {'a':100,'b':'foo'}
# 过滤条件
>>> mfields = {'a':fields.Raw}
# 过滤
>>> marshal(data,mfields)
OrderedDict([('a', 100)])
# 过滤后的数据,可以打包成 json数据
>>> import json
>>> json.dumps(marshal(data,mfields))
'{"a": 100}'
flask_restful.marshal_with(fields, envelope=None)
:一个装饰器,可以支持自定义函数,返回的效果和上一个相同.>>> from flask_restful import marshal_with
>>> mfields = {'a':fields.String}
>>> @marshal_with(mfields)
... def get():
... return {'a':'foo','b':100}
...
...
>>>
>>> get()
OrderedDict([('a', 'foo')])
>>> json.dumps(get())
'{"a": "foo"}'
处理一个复杂的结构:
# 过滤器,过滤条件,输出格式.
>>> resource_fields = {
... 'name':fields.String,
... 'address': {
... 'line1':fields.String,
... 'line2':fields.Integer,
... 'line3':fields.Raw
... }
... }
# 原始数据
>>> data = {
... 'name':'Jack',
... 'line1':'This is a test',
... 'line2':123,
... 'line3':'hello'
... }
# 组装成 OrderDict对象
>>> marshal(data,resource_fields)
OrderedDict([('name', 'Jack'), ('address', OrderedDict([('line1', 'This is a test'), ('line2', 123), ('line3', 'hello')]))])
# 生成Json数据
>>> json.dumps(marshal(date,resource_fields))
'{"name": "jack", "address": {"line1": null, "line2": 0, "line3": null}}'
也可以对列表进行处理:
# 需要处理的数据
>>> data = {
... 'book':'Python',
... 'detail':['price','description']
... }
# 过滤器
>>> resource_fields = {
... 'name': fields.String,
... 'detail':fields.List(fields.String)
... }
# 转化
>>> marshal(data,resource_fields)
OrderedDict([('name', None), ('detail', ['price', 'description'])])
# Json数据
>>> json.dumps(marshal(data,resource_fields))
'{"name": null, "detail": ["price", "description"]}'
fiels.List()
只能过滤一种数据类型
处理嵌套数据
fields.Nested
>>> data = {
... 'book':'Python',
... 'detail':{
... 'price':12,
... 'description':'This is a Python book.'
... }
... }
>>>
>>> resource_fields = {
... 'name': fields.String,
... 'detail':fields.List(fields.Nested({
... 'price':fields.Integer,
... 'description':fields.String
... }))
... }
>>>
>>> marshal(data,resource_fields)
OrderedDict([('name', None), ('detail', [OrderedDict([('price', 12), ('description', 'This is a Python book.')])])])
>>> json.dumps(marshal(data,resource_fields))
'{"name": null, "detail": [{"price": 12, "description": "This is a Python book."}]}'
– END –
原文始发于微信公众号(Flask学习笔记):Flask Restful
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/36431.html