Flask-RESTful 提供了一个简单的方式来控制在你的响应中实际呈现什么数据。
使用 fields 模块,你可以使用在你的资源里的任意对象(ORM 模型、定制的类等等)
并且 fields 让你格式化和过滤响应,因此您不必担心暴露内部数据结构。
from flask.ext.restful import Resource, fields, marshal_with
# 定义输出格式化字段
resource_fields = {
'name': fields.String,
'address': fields.String,
'date_updated': fields.DateTime(dt_format='rfc822'),
}
class Todo(Resource):
# 采用装饰器格式化
@marshal_with(resource_fields, envelope='resource')
# marshal_with 能够在单个对象,字典,或者列表对象上工作。
def get(self, **kwargs):
return db_get_todo() # 返回必须是对象
'''
这个例子假设你有一个自定义的数据库对象(todo),它具有属性:name, address, 以及 date_updated。该对象上任何其它的属性可以被认为是私有的不会在输出中呈现出来。
一个可选的 envelope 关键字参数被指定为封装结果输出。
'''
很多时候你面向公众的字段名称是不同于内部的属性名。使用 attribute 可以配置这种映射。
fields = {
'name': fields.String(attribute='private_name'),
'address': fields.String,
}
lambda 也能在 attribute 中使用
fields = {
'name': fields.String(attribute=lambda x: x._private_name),
'address': fields.String,
}
如果由于某种原因你的数据对象中并没有你定义的字段列表中的属性,你可以指定一个默认值而不是返回 None。
fields = {
'name': fields.String(default='Anonymous User'),
'address': fields.String,
}
当一个属性存储多条信息的时候是特别有用的。
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"
fields = {
'name': fields.String,
'priority': UrgentItem(attribute='flags'),
'status': UnreadItem(attribute='flags'),
}
Flask-RESTful 包含一个特别的字段,fields.Url,即为所请求的资源合成一个 uri。
class RandomNumber(fields.Raw):
def output(self, key, obj):
return random.random()
fields = {
'name': fields.String,
# todo_resource is the endpoint name when you called api.add_resource()
'uri': fields.Url('todo_resource'),
'random': RandomNumber,
}
默认情况下,fields.Url 返回一个相对的 uri。
为了生成包含协议(scheme),主机名以及端口的绝对 uri,需要在字段声明的时候传入 absolute=True。传入 scheme 关键字参数可以覆盖默认的协议(scheme)
fields = {
'uri': fields.Url('todo_resource', absolute=True)
'https_uri': fields.Url('todo_resource', absolute=True, scheme='https')
}
你可以有一个扁平的结构,marshal_with 将会把它转变为一个嵌套结构
>>> from flask.ext.restful import fields, marshal
>>> import json
>>>
>>> resource_fields = {'name': fields.String}
>>> resource_fields['address'] = {}
>>> resource_fields['address']['line 1'] = fields.String(attribute='addr1')
>>> resource_fields['address']['line 2'] = fields.String(attribute='addr2')
>>> resource_fields['address']['city'] = fields.String
>>> resource_fields['address']['state'] = fields.String
>>> resource_fields['address']['zip'] = fields.String
>>> data = {'name': 'bob', 'addr1': '123 fake street', 'addr2': '', 'city': 'New York', 'state': 'NY', 'zip': '10468'}
>>> json.dumps(marshal(data, resource_fields))
'{"name": "bob", "address": {"line 1": "123 fake street", "line 2": "", "state": "NY", "zip": "10468", "city": "New York"}}'
你也可以把字段解组(unmarshal)成列表
>>> from flask.ext.restful import fields, marshal
>>> import json
>>>
>>> resource_fields = {'name': fields.String, 'first_names': fields.List(fields.String)}
>>> data = {'name': 'Bougnazal', 'first_names' : ['Emile', 'Raoul']}
>>> json.dumps(marshal(data, resource_fields))
>>> '{"first_names": ["Emile", "Raoul"], "name": "Bougnazal"}'
>>> from flask.ext.restful import fields, marshal
>>> import json
>>>
>>> address_fields = {}
>>> address_fields['line 1'] = fields.String(attribute='addr1')
>>> address_fields['line 2'] = fields.String(attribute='addr2')
>>> address_fields['city'] = fields.String(attribute='city')
>>> address_fields['state'] = fields.String(attribute='state')
>>> address_fields['zip'] = fields.String(attribute='zip')
>>>
>>> resource_fields = {}
>>> resource_fields['name'] = fields.String
>>> resource_fields['billing_address'] = fields.Nested(address_fields)
>>> resource_fields['shipping_address'] = fields.Nested(address_fields)
>>> address1 = {'addr1': '123 fake street', 'city': 'New York', 'state': 'NY', 'zip': '10468'}
>>> address2 = {'addr1': '555 nowhere', 'city': 'New York', 'state': 'NY', 'zip': '10468'}
>>> data = { 'name': 'bob', 'billing_address': address1, 'shipping_address': address2}
>>>
>>> json.dumps(marshal_with(data, resource_fields))
'{"billing_address": {"line 1": "123 fake street", "line 2": null, "state": "NY", "zip": "10468", "city": "New York"}, "name": "bob", "shipping_address": {"line 1": "555 nowhere", "line 2": null, "state": "NY", "zip": "10468", "city": "New York"}}'