python - 将 StreamingHttpResponse 与 Django Rest Framework CSV 一起使用

标签 python django rest csv django-rest-framework

我有一个标准的 DRF 网络应用程序,可以为其中一条路线输出 CSV 数据。呈现整个 CSV 表示需要一段时间才能完成。数据集非常大,所以我想要一个流式 HTTP 响应,这样客户端就不会超时。

但是使用 https://github.com/mjumbewu/django-rest-framework-csv/blob/2ff49cff4b81827f3f450fd7d56827c9671c5140/rest_framework_csv/renderers.py#L197 中提供的示例并没有完全做到这一点。数据仍然是一个很大的有效载荷,而不是被分 block ,客户端最终在接收到字节之前等待响应。

结构类似如下:

模型.py

class Report(models.Model):
  count = models.PostiveIntegerField(blank=True)
  ...

渲染器.py

class ReportCSVRenderer(CSVStreamingRenderer):
  header = ['count']

序列化器.py

class ReportSerializer(serializers.ModelSerializer):
  count = fields.IntegerField()

  class Meta:
    model = Report

views.py

class ReportCSVView(generics.Viewset, mixins.ListModelMixin):
  def get_queryset(self):
    return Report.objects.all()

  def list(self, request, *args, **kwargs):
    queryset = self.get_queryset()
    data = ReportSerializer(queryset, many=True)
    renderer = ReportCSVRenderer()

    response = StreamingHttpResponse(renderer.render(data), content_type='text/csv')
    response['Content-Disposition'] = 'attachment; filename="f.csv"'

    return response

注意:必须注释掉或更改一些内容。

谢谢

最佳答案

一个更简单的解决方案,灵感来自 @3066d0 的解决方案:

渲染器.py

class ReportsRenderer(CSVStreamingRenderer):
    header = [ ... ]
    labels = { ... }

views.py

class ReportCSVViewset(ListModelMixin, GenericViewSet):
    queryset = Report.objects.select_related('stuff')
    serializer_class = ReportCSVSerializer
    renderer_classes = [ReportsRenderer]
    PAGE_SIZE = 1000

    def list(self, request, *args, **kwargs):
        queryset = self.filter_queryset(self.get_queryset())
        response = StreamingHttpResponse(
            request.accepted_renderer.render(self._stream_serialized_data(queryset)),
            status=200,
            content_type="text/csv",
        )
        response["Content-Disposition"] = 'attachment; filename="reports.csv"'
        return response

    def _stream_serialized_data(self, queryset):
        serializer = self.get_serializer_class()
        paginator = Paginator(queryset, self.PAGE_SIZE)
        for page in paginator.page_range:
            yield from serializer(paginator.page(page).object_list, many=True).data

重点是您需要将生成序列化数据的生成器作为 data 参数传递给渲染器,然后 CSVStreamingRenderer 执行其操作并流式传输响应本身。我更喜欢这种方法,因为这样你就不需要覆盖第三方库的代码。

关于python - 将 StreamingHttpResponse 与 Django Rest Framework CSV 一起使用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46694898/

相关文章:

python - 查找二维数组中最后一次出现的最大值

python - 提高我的 XOR 程序的时间和空间效率

python - Django 迁移。如何检查迁移中是否存在表?

python - 我可以安全地删除 Django 的空 __init__ 文件吗?

ruby-on-rails - 带有嵌套参数 cUrl 的多部分 POST

javascript - 如何为 Node.js REST API 正确配置 Nginx?

Python Google App Engine Cron 作业/计划任务不工作

python - 数据框中的条件新列

python - 对于 django 模型的任何查询,仅对事件设置为 true 的元素执行查询

Java REST 实现 : Jersey vs CXF