Skip to main content

使用Django输出PDF

本文解释如何使用Django视图动态输出PDF文件。这是通过优秀的,开源的 ReportLab Python PDF库实现的。

动态生成PDF文件的优点是,您可以为不同用途(例如,针对不同用户或不同内容)创建自定义PDF。

例如,Django用于 kusports.com,为参加3月疯狂竞赛的人们生成定制的,打印友好的NCAA锦标赛支架,作为PDF文件。

安装ReportLab

ReportLab库是 available on PyPIuser guide (不是巧合的,PDF文件)也可以下载。您可以使用 pip 安装ReportLab:

$ pip install reportlab

通过在Python交互式解释器中导入它来测试安装:

>>> import reportlab

如果该命令没有引起任何错误,安装工作。

写你的看法

使用Django动态生成PDF的关键是ReportLab API对类文件对象起作用,Django的 HttpResponse 对象是类文件对象。

这里是一个“Hello World”的例子:

from reportlab.pdfgen import canvas
from django.http import HttpResponse

def some_view(request):
    # Create the HttpResponse object with the appropriate PDF headers.
    response = HttpResponse(content_type='application/pdf')
    response['Content-Disposition'] = 'attachment; filename="somefilename.pdf"'

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

    # 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()
    return response

代码和注释应该是不言自明的,但有几件事值得一提:

  • 响应获取特殊的MIME类型 application/pdf。这告诉浏览器文档是一个PDF文件,而不是一个HTML文件。如果你把它关闭,浏览器可能会将输出解释为HTML,这将导致在浏览器窗口丑陋,可怕的gobbledygook。

  • 响应获取一个附加的 Content-Disposition 头,其中包含PDF文件的名称。这个文件名是任意的:无论你想要什么。它将由浏览器在“另存为...”对话框等中使用。

  • 在此示例中,Content-Disposition 头以 'attachment; ' 开头。这将强制Web浏览器弹出一个对话框,提示/确认如何处理文档,即使在机器上设置了默认值。如果您离开 'attachment;',浏览器将使用任何已配置为用于PDF的程序/插件处理PDF。这里的代码看起来像:

    response['Content-Disposition'] = 'filename="somefilename.pdf"'
    
  • 挂钩到ReportLab API很容易:只需传递 response 作为 canvas.Canvas 的第一个参数。 Canvas 类需要一个类似于文件的对象,HttpResponse 对象适合bill。

  • 请注意,在PDF对象(本例中为 p)中调用所有后续的PDF生成方法,而不是在 response 上。

  • 最后,在PDF文件上调用 showPage()save() 很重要。

注解

ReportLab不是线程安全的。我们的一些用户报告了建立PDF生成Django视图奇怪的问题,许多人同时访问。

复杂PDF

如果要使用ReportLab创建复杂的PDF文档,请考虑使用 io 库作为PDF文件的临时保留位置。这个库提供了一个特别有效的文件式对象接口。这里是上面的“Hello World”示例改写为使用 io:

from io import BytesIO
from reportlab.pdfgen import canvas
from django.http import HttpResponse

def some_view(request):
    # Create the HttpResponse object with the appropriate PDF headers.
    response = HttpResponse(content_type='application/pdf')
    response['Content-Disposition'] = 'attachment; filename="somefilename.pdf"'

    buffer = BytesIO()

    # Create the PDF object, using the BytesIO object 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.
    p.showPage()
    p.save()

    # Get the value of the BytesIO buffer and write it to the response.
    pdf = buffer.getvalue()
    buffer.close()
    response.write(pdf)
    return response

其他格式

注意,这些示例中没有很多是特定于PDF的 - 只是使用 reportlab 的位。您可以使用类似的技术来生成任何可以找到Python库的任意格式。另请参阅 使用Django输出CSV 另一个示例和一些技术,您可以使用时生成的基于文本的格式。

参见

Django Packages提供了一个帮助从Django生成PDF文件的 比较包