Mig*_*ell 7 csv mime-types graphql graphene-python
普通的 REST API 可能会让您以不同的格式请求相同的数据,并使用不同的Accept标头,例如application/json、 或text/html,或text/csv格式化响应。
但是,如果您使用 GraphQL,则 JSON 似乎是唯一可接受的返回内容类型。但是,我需要我的 API 能够返回 CSV 数据,以供无法理解 JSON 的不太复杂的客户端使用。
如果给定标头,GraphQL 端点返回 CSV 数据是否有意义Accept: text/csv?如果没有,是否有更好的练习方法来做到这一点?
这更多的是一个概念性问题,但我专门使用石墨烯来实现我的 API。它是否提供任何处理自定义内容类型的机制?
小智 5
是的,你可以,但它不是内置的,你必须覆盖一些东西。这更像是一种解决方法。
执行以下步骤,您将获得 csv 输出:
添加csv = graphene.String()您的查询并将其解决为您想要的任何内容。
创建一个新类继承GraphQLView
重写dispatch函数看起来像这样:
def dispatch(self, request, *args, **kwargs):
response = super(CustomGraphqlView, self).dispatch(request, *args, **kwargs)
try:
data = json.loads(response.content.decode('utf-8'))
if 'csv' in data['data']:
data['data'].pop('csv')
if len(list(data['data'].keys())) == 1:
model = list(data['data'].keys())[0]
else:
raise GraphQLError("can not export to csv")
data = pd.json_normalize(data['data'][model])
response = HttpResponse(content_type='text/csv')
response['Content-Disposition'] = 'attachment; filename="output.csv"'
writer = csv.writer(response)
writer.writerow(data.columns)
for value in data.values:
writer.writerow(value)
except GraphQLError as e:
raise e
except Exception:
pass
return response
Run Code Online (Sandbox Code Playgroud)
导入所有必要的模块
GraphQLView将文件中的默认值替换urls.py为新的视图类。
现在,如果您在 GraphQL 查询中包含“csv”,它将返回原始 csv 数据,然后您可以将数据保存到前端的 csv 文件中。示例查询如下:
query{
items{
id
name
price
category{
name
}
}
csv
}
Run Code Online (Sandbox Code Playgroud)
请记住,这是一种获取 csv 格式的原始数据的方法,您必须保存它。您可以使用以下代码在 JavaScript 中执行此操作:
req.then(data => {
let element = document.createElement('a');
element.setAttribute('href', 'data:text/csv;charset=utf-8,' + encodeURIComponent(data.data));
element.setAttribute('download', 'output.csv');
element.style.display = 'none';
document.body.appendChild(element);
element.click();
document.body.removeChild(element);
})
Run Code Online (Sandbox Code Playgroud)
此方法会展平 JSON 数据,因此不会丢失任何数据。
GraphQL 依赖于(并因此而发光)响应嵌套数据。据我了解,CSV 只能显示平面键值对。这使得 CSV 不太适合 GraphQL 响应。
我认为实现您想要做的事情的最干净的方法是将 GraphQL 客户端放在您的客户面前:
+------+ csv +-------+ http/json +------+
|client|<----->|adapter|<----------->|server|
+------+ +-------+ +------+
Run Code Online (Sandbox Code Playgroud)
这里的好处是您的适配器只需能够将其指定的查询转换为 CSV。
显然你可能并不总是能够这样做(但是你如何让他们发送 GraphQL 查询)。或者,您可以构建一个将 JSON 转换为 CSV 的中间件。但接下来你必须处理整个 GraphQL 规范。祝你翻译此回复好运:
{
"__typename": "Query",
"someUnion": [
{ "__typename": "UnionA", "numberField": 1, "nested": [1, 2, 3, 4] },
{ "__typename": "UnionB", "stringField": "str" },
],
"otherField": 123.34
}
Run Code Online (Sandbox Code Playgroud)
因此,如果您无法通过 HTTP 传输 CSV,那么 GraphQL 就是错误的选择,因为它不是为此而构建的。如果您不允许那些难以转换为 CSV 的 GraphQL 功能,那么您就不再拥有 GraphQL,因此将其称为 GraphQL 就没有意义了。