Python Flask Rest Plus-返回响应对象及其描述

时间:2019-09-12 23:26:11

标签: python flask-restplus

我正在使用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

一切都失败,并出现相同的错误。

3 个答案:

答案 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