跳转到主内容
新派编程网 - 新潮编程理念,全新技术课堂!

Restful规范响应处理(marshal、marshal_with、fields、reqparse、representation)

1、Restful规范返回值 对于一个类视图,可以指定好一些字段做标准化用于返回。

以后使用ORM模型或者自定义模型的时候,他会自动的获取模型中的相应的字段,生成json格式数据,然后再返回给客户端。

使用方法 : 导入 flask_restful.marshal_with 装饰器 定义一个字典变量来指定需要返回的标准化字段,以及该字段的数据类型 在请求方法中,返回自定义对象的时候,flask_restful会自动的读取对象模型上的所有属性。

组装成一个符合标准化参数的json格式字符串返回给客户端 示例代码:

from flask import Flask

from flask_restful import Api, Resource, fields, marshal_with

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

class News: def __init__(self, code, msg, state, content): self.code = code self.msg = msg self.state = state self.content = content

class NewsView(Resource): resouce_fields = { 'code': fields.Integer, 'msg': fields.String, 'state': fields.String }

@marshal_with(resouce_fields) def get(self): return {'code': 200, 'msg': '访问成功!

', 'state': 'OK'}

@marshal_with(resouce_fields) def post(self): return {'msg': '注册成功!

'}

@marshal_with(resouce_fields) def put(self): # 在返回对象时,会自动在对象中获取与约定好的字段,并获取封装成json。

news = News(404, '注册成功', 'OK', 'dgw') return news

api.add_resource(NewsView, '/news/')

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

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

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()

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

class Todo(Resource):

def get(self, **kwargs): data = db_get_todo() return marshal(data, resource_fields)

示例代码1:

from flask import Flask

from flask_restful import fields, Resource, marshal, marshal_with, Api

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

# 用来模拟要返回的数据对象的类 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, 'dgw', 12) return user

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

api.add_resource(Demo1Resource, '/demo1') api.add_resource(Demo2Resource, '/demo2')

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

运行效果:

测试代码2:

运行结果:

示例代码3:

from flask import Flask

from flask_restful import reqparse, Api, Resource, fields, marshal_with

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

# 1. 关于参数解析的部分 # 一组虚拟的数据 TODOS = { 'todo1': {'task': 1}, 'todo2': {'task': 2}, 'todo3': {'task': 3}, }

# 定义允许的参数为task,类型为int,以及错误时的提示 parser = reqparse.RequestParser() parser.add_argument('task', type=int, help='Please set a int task content!')

# 真正处理请求的地方 class TodoList(Resource): def get(self): return TODOS, 200, {'Etag': 'some-opaque-string'}

def post(self): args = parser.parse_args() print(max(TODOS.keys()), type(max(TODOS.keys()))) todo_id = int(max(TODOS.keys()).lstrip('todo')) + 1 todo_id = 'todo%i' % todo_id TODOS[todo_id] = {'task': args['task']} return TODOS[todo_id], 201

# 实际定义路由的地方 api.add_resource(TodoList, '/todos', '/all_tasks')

# 2. 关于响应域的部分 # ORM的数据模型 class TodoDao(object): def __init__(self, todo_id, task): self.todo_id = todo_id self.task = task

# 这个域不会被返回 self.status = 'active'

# marshal-蒙板, resource_fields = { 'task': fields.String, 'url': fields.Url('todo_ep') }

# 真正处理请求的地方 class Todo(Resource): # 蒙板 把多余的参数蒙住,只返回resource_fields中声明的键值对 @marshal_with(resource_fields) def get(self, todo_id): return TodoDao(todo_id=todo_id, task='Remember the milk'), 200

# 实际定义路由的地方 api.add_resource(Todo, '/todos/', endpoint='todo_ep') # 类Todo中只写了get方法

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

运行结果: get功能:

post功能:

3、Restful规范返回值-参数设置 3.1 设置重命名属性和默认值 问题:规范给出的属性名和模型内部的属性名不相同?

答:使用 attribute 配置这种映射,比如: fields.String(attribute='username') 问题:某些字段,没有值,但想给一个值做为默认值?

答:使用 default 指定默认值,比如: fields.String(default='sxt') 示例代码:

from flask import Flask

from flask_restful import Api, Resource, fields, marshal_with

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

class News: def __init__(self, code, msg, info): self.code = code self.msg = msg self.info = info self.state = 1000

class NewsView(Resource): resouce_fields = { 'code': fields.Integer(default=200), # 通过参数default来设置默认值 'msg': fields.String, 'content': fields.String(attribute='info'), # 通过参数attribute来设置提取数据的字段 'state': fields.Integer(default=2000) # 优先级不如真实数据里面的高 }

@marshal_with(resouce_fields) def get(self): news = News(200, '访问成功!

', '移动') return news

@marshal_with(resouce_fields) def post(self): return {'msg': '增加数据成功!

', 'info': '联通'}

@marshal_with(resouce_fields) def put(self): news = News(200, '访问成功!

', '移动') return news

api.add_resource(NewsView, '/news/')

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

运行结果:

4、Restful规范返回值-类型设置 大型的互联网项目中,返回的数据格式,有时是比较复杂的结构。

如:豆瓣电影

返回的值里有json或者列表数据,这时可以通过以字段来实现 fields.List 放置一个列表 fields.Nested放置一个字典 示例代码:

from flask import Flask

from flask_restful import Api, Resource, fields, marshal_with

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

class User: def __init__(self, uname): self.uname = uname

def __repr__(self): return f''

class NewsType: def __init__(self, _type): self._type = _type

def __repr__(self): return f''

class News: def __init__(self, code, msg): self.code = code self.msg = msg self.user = None self._type = []

def __repr__(self): return f''

def create_data(): user = User('dgw') _type1 = NewsType('IT') _type2 = NewsType('Python') news = News(200, 'Python update!

') news.user = user news._type.append(_type1) news._type.append(_type2)

return news

class NewsView(Resource): resouce_fields = { 'code': fields.Integer, 'msg': fields.String, 'user': fields.Nested({ 'uname': fields.String }), '_type': fields.List(fields.Nested({ '_type': fields.String })) }

@marshal_with(resouce_fields) def get(self): news = create_data() print(news) print(type(news)) return news

api.add_resource(NewsView, '/news/')

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

运行结果:

5、定制返回的JSON格式 5.1 需求 想要接口返回的JSON数据具有如下统一的格式

{"message": "描述信息", "data": {要返回的具体数据}}

在接口处理正常的情况下, message返回ok即可,但是若想每个接口正确返回时省略message字段

class DemoResource(Resource):

def get(self): return {'user_id':1, 'name': 'itcast'}

对于诸如此类的接口,能否在某处统一格式化成上述需求格式?

{"message": "OK", "data": {'user_id':1, 'name': 'itcast'}}

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

api = Api(app)

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

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

flask_restful.representations.json 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

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

@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 示例代码:

from flask import Flask

from flask_restful import Api, Resource, fields, marshal_with from flask import make_response, current_app from flask_restful.utils import PY3 from json import dumps

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

@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

class NewsView(Resource): resouce_fields = { 'code': fields.Integer, 'msg': fields.String, 'state': fields.String }

@marshal_with(resouce_fields) def get(self): return {'code': 200.1, 'msg': '访问成功!

', 'state': 'OK'}

api.add_resource(NewsView, '/news')

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

运行结果:

相关文章