用Django输出PDF

本文档介绍了如何使用Django视图动态输出PDF文件。 这是由优秀的开放源码的ReportLab Python PDF库实现的。

动态生成PDF文件的优势在于,您可以为不同的目的创建自定义的PDF - 例如,针对不同的用户或不同的内容。

例如,Django在kusports.com中用于为参与三月疯狂比赛的人们生成定制的,打印友好的NCAA锦标赛括号,如PDF文件。

安装ReportLab

The ReportLab library is available on PyPI. 一个用户指南(不一致,一个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对象适合账单。

  • 请注意,所有后续的PDF生成方法都在PDF对象(在本例中为p)上调用,而不是在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库的任意格式。 另请参阅Outputting CSV with Django作为另一个示例,以及在生成基于文本的格式时可以使用的一些技巧。

也可以看看

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