我正在使用Python Flask RestPlus框架,这是Python的新手。尝试发送回响应对象以及一些描述和状态代码,但失败并出现以下错误:
TypeError: Object of type Response is not JSON serializable
这就是我在做什么
from flask import jsonify, Response
from flask_restplus import Resource
class MyUsage(Resource):
def get(self):
# Do something
return "My Description" + jsonify(myObject), 200
我什至尝试发送如下对象:
result = {'Desc': 'My Description',
'Result': jsonify(myObject)}
return result, 200
和
return jsonify('Desc': 'My Description',
'Result': myObject), 200
一切都失败,并出现相同的错误。
答案 0 :(得分:2)
jsonify
将不会序列化对象。它用于将字典转换为有效的JSON响应(对此可能会有一些例外)。
有几种方法可以解决此问题。我个人最喜欢的是marshmallow
库,因为您可以使用它来将请求数据反序列化为对象,同时还可以验证数据并将对象序列化为字典。这样,您的对象就永远不会在无效状态下实例化。
另一种可能更容易但可扩展性较低的方法是为对象编写一个to_data
方法。
class Object():
def __init__(self, a, b):
self.a = a
self.b = b
def to_data(self):
return {
'a': self.a,
'b', self.b
}
您可以使用此方法序列化对象。
myObject = Object(1,2)
data = myObject.to_data()
return jsonify(data), 200
答案 1 :(得分:0)
就像@Kevin所说的,
jsonify
将不会序列化对象。它用于转换 字典到有效的JSON响应(以下内容可能会有一些例外 这个)。
我将提供另一种解决方案。
我注意到您的代码中使用了flask_restplus
,实际上flask_restplus将自动执行jsonfy。以下源代码来自flask_rest
def make_response(self, data, *args, **kwargs):
'''
Looks up the representation transformer for the requested media
type, invoking the transformer to create a response object. This
defaults to default_mediatype if no transformer is found for the
requested mediatype. If default_mediatype is None, a 406 Not
Acceptable response will be sent as per RFC 2616 section 14.1
:param data: Python object containing response data to be transformed
'''
default_mediatype = kwargs.pop('fallback_mediatype', None) or self.default_mediatype
mediatype = request.accept_mimetypes.best_match(
self.representations,
default=default_mediatype,
)
if mediatype is None:
raise NotAcceptable()
if mediatype in self.representations:
resp = self.representations[mediatype](data, *args, **kwargs)
resp.headers['Content-Type'] = mediatype
return resp
elif mediatype == 'text/plain':
resp = original_flask_make_response(str(data), *args, **kwargs)
resp.headers['Content-Type'] = 'text/plain'
return resp
else:
raise InternalServerError()
并且self.representations的媒体类型为application/json
,这意味着当请求的媒体类型为application/json
时,响应将使用representations['application/json']
函数来构建响应。
然后会调用
def output_json(data, code, headers=None):
'''Makes a Flask response with a JSON encoded body'''
settings = current_app.config.get('RESTPLUS_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.
if current_app.debug:
settings.setdefault('indent', 4)
# 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
话虽如此,您可以在烧瓶RESTPLUS_JSON
中设置app.config
例如,datetime不是可序列化的对象,因此可以为该类型提供一个转换器,如以下代码所示。
首先,您需要定义一个转换器:
def datetime_json_converter(o):
if isinstance(o, datetime.datetime):
return o.__str__()
然后,您只需要在烧瓶RESTPLUS_JSON
中设置app.config
app.config['RESTPLUS_JSON'] = {'default': datetime_json_converter}
答案 2 :(得分:0)
最好的解决方案之一是使用编组。 首先,您需要编写一个模型,说明您要使用对象的哪些属性以及每个属性的类型。
from flask_restplus import Resource, fields
model = api.model('Model', {
'name': fields.String,
'address': fields.String,
'date_updated': fields.DateTime(dt_format='rfc822'),
})
然后你需要将它应用到你想要的资源方法上。
@api.route('/<id>')
class Todo(Resource):
@api.marshal_with(model) <-- Here you refer the model you created above
def get(self, id):
# find or prepare your object and just return that object
return object