生成 PDF 文件

便携文档格式 (PDF) 是由 Adobe 开发的格式,主要用于呈现可打印的文档,其中包含有 pixel-perfect 格式,嵌入字体以及2D矢量图像。 You can think of a PDF document as the digital equivalent of a printed document; indeed, PDFs are often used in distributing documents for the purpose of printing them.

可以方便的使用 Python 和 Django 生成 PDF 文档需要归功于一个出色的开源库, ReportLab (http://www.reportlab.org/rl_toolkit.html) 。动态生成 PDF 文件的好处是在不同的情况下,如不同的用户或者不同的内容,可以按需生成不同的 PDF 文件。 The advantage of generating PDF files dynamically is that you can create customized PDFs for different purposes say, for different users or different pieces of content.

下面的例子是使用 Django 和 ReportLab 在 KUSports.com 上生成个性化的可打印的 NCAA 赛程表 (tournament brackets) 。

安装 ReportLab

在生成 PDF 文件之前,需要安装 ReportLab 库。这通常是个很简单的过程: Its usually simple: just download and install the library from http://www.reportlab.org/downloads.html.

Note

如果使用的是一些新的 Linux 发行版,则在安装前可以先检查包管理软件。 多数软件包仓库中都加入了 ReportLab 。

比如,如果使用(杰出的) Ubuntu 发行版,只需要简单的 apt-get install python-reportlab 一行命令即可完成安装。

使用手册(原始的只有 PDF 格式)可以从 >http://www.reportlab.org/rsrc/userguide.pdf 下载,其中包含有一些其它的安装指南。

在 Python 交互环境中导入这个软件包以检查安装是否成功。

  1. >>> import reportlab

如果刚才那条命令没有出现任何错误,则表明安装成功。

编写视图

和 CSV 类似,由 Django 动态生成 PDF 文件很简单,因为 ReportLab API 同样可以使用类似文件对象。

下面是一个 Hello World 的示例:

  1. from reportlab.pdfgen import canvas
  2. from django.http import HttpResponse
  3. def hello_pdf(request):
  4. # Create the HttpResponse object with the appropriate PDF headers.
  5. response = HttpResponse(mimetype='application/pdf')
  6. response['Content-Disposition'] = 'attachment; filename=hello.pdf'
  7. # Create the PDF object, using the response object as its "file."
  8. p = canvas.Canvas(response)
  9. # Draw things on the PDF. Here's where the PDF generation happens.
  10. # See the ReportLab documentation for the full list of functionality.
  11. p.drawString(100, 100, "Hello world.")
  12. # Close the PDF object cleanly, and we're done.
  13. p.showPage()
  14. p.save()
  15. return response

需要注意以下几点:

  • 这里我们使用的 MIME 类型是 application/pdf 。这会告诉浏览器这个文档是一个 PDF 文档,而不是 HTML 文档。 如果忽略了这个参数,浏览器可能会把这个文件看成 HTML 文档,这会使浏览器的窗口中出现很奇怪的文字。 If you leave off this information, browsers will probably interpret the response as HTML, which will result in scary gobbledygook in the browser window.

  • 使用 ReportLab 的 API 很简单: 只需要将 response 对象作为 canvas.Canvas 的第一个参数传入。

  • 所有后续的 PDF 生成方法需要由 PDF 对象调用(在本例中是 p ),而不是 response 对象。

  • 最后需要对 PDF 文件调用 showPage()save() 方法(否则你会得到一个损坏的 PDF 文件)。

复杂的 PDF 文件

如果您在创建一个复杂的 PDF 文档(或者任何较大的数据块),请使用 cStringIO 库存放临时生成的 PDF 文件。 cStringIO 提供了一个用 C 编写的类似文件对象的接口,从而可以使系统的效率最高。

下面是使用 cStringIO 重写的 Hello World 例子:

  1. from cStringIO import StringIO
  2. from reportlab.pdfgen import canvas
  3. from django.http import HttpResponse
  4. def hello_pdf(request):
  5. # Create the HttpResponse object with the appropriate PDF headers.
  6. response = HttpResponse(mimetype='application/pdf')
  7. response['Content-Disposition'] = 'attachment; filename=hello.pdf'
  8. temp = StringIO()
  9. # Create the PDF object, using the StringIO object as its "file."
  10. p = canvas.Canvas(temp)
  11. # Draw things on the PDF. Here's where the PDF generation happens.
  12. # See the ReportLab documentation for the full list of functionality.
  13. p.drawString(100, 100, "Hello world.")
  14. # Close the PDF object cleanly.
  15. p.showPage()
  16. p.save()
  17. # Get the value of the StringIO buffer and write it to the response.
  18. response.write(temp.getvalue())
  19. return response