13

我有一个大型数据集,我必须为其生成 CSV 和 PDF。对于 CSV,我使用本指南:https ://docs.djangoproject.com/en/3.1/howto/outputting-csv/

import csv

from django.http import StreamingHttpResponse

class Echo:
    """An object that implements just the write method of the file-like
    interface.
    """
    def write(self, value):
        """Write the value by returning it, instead of storing in a buffer."""
        return value

def some_streaming_csv_view(request):
    """A view that streams a large CSV file."""
    # Generate a sequence of rows. The range is based on the maximum number of
    # rows that can be handled by a single sheet in most spreadsheet
    # applications.
    rows = (["Row {}".format(idx), str(idx)] for idx in range(65536))
    pseudo_buffer = Echo()
    writer = csv.writer(pseudo_buffer)
    response = StreamingHttpResponse((writer.writerow(row) for row in rows),
                                     content_type="text/csv")
    response['Content-Disposition'] = 'attachment; filename="somefilename.csv"'
    return response

它工作得很好。但是,我找不到可以为 PDF 做的任何事情。它可以?我使用render_to_pdf和使用 PDF 模板一样。

4

4 回答 4

2

将 CSV 视为水果沙拉。您可以在一个大锅中将香蕉切片,加入一些葡萄柚、一些菠萝……然后将整个香蕉分成单独的部分,然后放在餐桌上(这是:您生成 CSV 文件,然后将其发送到客户端)。但是你也可以直接做单独的部分:在一个小碗里切一些香蕉片,加入一些葡萄柚,一些菠萝,......把这个小碗带到桌子上,然后对其他单独的部分重复这个过程(这是:您生成 CSV 文件并在生成时将其部分发送给客户端)。

好吧,如果 CSV 是水果沙拉,那么 PDF 就是蛋糕。您必须混合所有成分并将其放入烤箱中。这意味着在烤完整个蛋糕之前,您不能将一片蛋糕带到餐桌上。同样,在完全生成 PDF 文件之前,您不能开始将其发送给客户端。

因此,要回答您的问题,此 ( response = StreamingHttpResponse((writer.writerow(row) for row in rows), content_type="text/csv")) 不能用于 PDF。

但是,一旦您的文件生成FileResponse,您可以使用其他答案中提到的将其流式传输到客户端。

如果您的问题是 PDF 的生成花费了太多时间(例如,可能会触发超时错误),请考虑以下几点:

  1. 尝试优化生成算法的速度
  2. 在客户端请求之前在后台生成文件并将其存储在您的存储系统中。您可能希望使用 cronjob 或celery来触发 PDF 的生成,而不会阻止 HTTP 请求。
  3. 准备好下载后,使用 websockets 将文件发送到客户端(请参阅django-channels
于 2020-11-13T02:05:09.323 回答
1

你试过FileResponse吗?

像这样的东西应该可以工作,基本上你可以在Django doc中找到它:

import io
from django.http import FileResponse
from reportlab.pdfgen import canvas

def stream_pdf(request):
    buffer = io.BytesIO()
    p = canvas.Canvas(buffer)
    p.drawString(10, 10, "Hello world.")
    p.showPage()
    p.save()
    buffer.seek(io.SEEK_SET)
    return FileResponse(buffer, as_attachment=True, filename='helloworld.pdf')
于 2020-08-13T20:27:06.377 回答
0

查看您提供的链接,它确实提供了指向使用reportlab动态创建和发送 pdf 文件的页面的链接。

import io
from django.http import FileResponse
from reportlab.pdfgen import canvas

def some_view(request):
    # Create a file-like buffer to receive PDF data.
    buffer = io.BytesIO()

    # Create the PDF object, using the buffer as its "file."
    p = canvas.Canvas(buffer)

    # Draw things on the PDF. Here's where the PDF generation happens.
    # See the ReportLab documentation for the full list of functionality.
    p.drawString(100, 100, "Hello world.")

    # Close the PDF object cleanly, and we're done.
    p.showPage()
    p.save()

    # FileResponse sets the Content-Disposition header so that browsers
    # present the option to save the file.
    buffer.seek(0)
    return FileResponse(buffer, as_attachment=True, filename='hello.pdf')

这是reportlab api文档的链接。它有点冗长,并且存储在令人讨厌的单页 pdf 中,但它应该能让你启动并运行,并且能够根据需要很好地格式化 PDF。

于 2020-08-20T14:31:20.380 回答
0

我有类似的情况,我能够“生成和流式下载”和类型的文件csv,我想对Excel文件做同样的事情。jsonxmlxlsx

不幸的是,我做不到。但是,在那段时间我发现了一些东西

  1. 文件、CSV、JSON 和 XML 是具有适当表示的文本文件。但是,对于 PDF 或 Excel(或类似文件),这些文件是用正确的格式和正确的元数据构建的。

  2. PDF 和类似文档的二进制数据只有在我们调用某些特定方法时才会写入io 缓冲区。[showPage()save()方法reportlab。(来源- Django Doc)]

  3. 如果我们检查文件流,PDF 和 Excel 需要复杂的特殊应用程序(例如:PDF 阅读器、Bowsers 等)来查看/读取数据,而使用 CSV 和 JSON,我们只需要一个简单的文本编辑器。

因此,我得出结论,“通过流下载动态生成文件”的过程(不确定我应该使用的正确技术术语是什么)并非适用于所有文件类型,而仅适用于少数面向文本的文件

注意:这是我有限的经验,可能是错误的。

于 2020-08-13T15:56:52.220 回答