Flask api 表示影响所有视图

Flask api representation affects all the views

我需要有两个逻辑相同的视图来响应不同内容类型的相同数据。我使用 Flask RESTful.

APP = flask.Flask(__name__)
API = flask_restful.Api(APP)

@API.representation('text/csv')                                               
def output_csv(data, code, headers=None):                                     
    data_is_list = isinstance(data, types.ListType)                           
    keys = data[0].keys() if data_is_list else data.keys()                    
    output = io.BytesIO()                                                     
    writer = csv.DictWriter(output, keys)                                     
    writer.writeheader()                                                      
    encode = lambda v: v.encode('utf-8') if isinstance(                       
            v, types.UnicodeType) else v                                      
    if data_is_list:                                                          
        writer.writerows([{k: encode(v) for k, v in i.items()} for i     in data])
    else:                                                                     
        writer.writerow({k: encode(v) for k, v in data.items()})              

    resp = flask.make_response(output.getvalue(), code)                       
    resp.headers.extend(headers or {})                                        

    return resp                                                               


class BaseAction(flask_restful.Resource):
    def get(self, id=None):
        # ...
        return actions[0] if id else actions # Dict or list of dicts.


class ActionAsCSV(BaseAction):
    def get(self, id=None):
        data = super(ActionAsCSV, self).get(id, closed)
        flask.Response(data, mimetype='text/csv')      
        return data                                    

有几个问题。在我添加了表示视图之后,所有视图 return text/csv 数据都具有适当的 header。 如何使用第一个视图 class 到 return application/json 数据和第二个视图到 return text/csv 数据?第二个问题是 CSV get 方法的 return 值,如果我 return 响应 object return flask.Response(data, mimetype='text/csv') 数据变得格式错误 - 只有键没有值。 如何在不损坏数据的情况下启用不同的 mimetype?

首先,请注意您不应将相同的资源用于 return 单个操作或操作列表。您应该使用两种不同的资源:

class Action(flask_restful.Resource):
    def get(self, action_id):
        return actions[action_id]

class ActionList(flask_restful.Resource):
    def get(self):
        return actions

那么,return 同一资源的不同媒体类型的最简单方法是使用内容协商。在这种情况下,您无需声明专用资源 ActionAsCSV 来专门处理 return 以 CSV 格式响应的情况。例如,使用 curl:

的内容协商

curl -iH "Accept: text/csv" http://URL_TO_YOUR_VIEW

此外,Flask-RESTful会自动为您添加正确的content-type header returned 回复:您不需要在资源的 get 方法中定义它。

此外,API 默认配置为 JSON 中的 return 表示。但是,您可以按如下方式修改它:

api = flask_restful.Api(app, default_mediatype="text/csv")

如果您绝对想要两个不同的资源来处理 application/jsontext/csv,则不使用内容协商且无后备媒体类型,这是可能的:

api = flask_restful.Api(app, default_mediatype=None)

class ActionListMixin(object):
    def get(self):
        return actions

class JsonActionList(ActionListMixin, flask_restful.Resource):
    representations = {'application/json': output_json}

class CsvActionList(ActionListMixin, flask_restful.Resource):
    representations = {'text/csv': output_csv}

另一个类似的选项是在添加资源时定义表示转换器:

api = flask_restful.Api(app, default_mediatype=None)

class ActionList(flask_restful.Resource):
    def __init__(self, representations=None):
        self.representations = representations
        super(ActionList, self).__init__()

    def get(self):
        return actions

api.add_resource(ActionList, '/actions_json', resource_class_kwargs={'representations': {'application/json': output_json}})
api.add_resource(ActionList, '/actions_csv', resource_class_kwargs={'representations': {'text/csv': output_csv}})