利用 Django 输出 PDF

本文介绍如何用 Django 的视图动态输出 PDF 文件。该功能由绝佳的开源 ReportLab Python PDF 库提供。

动态生成 PDF 文件的优点是你可以为不同的目的创建不同的自定义 PDF——例如,为不同的用户或内容的不同片段生成 PDF。

例如,kusports.com 用 Django 将自定义的,打印友好的 NCAA 锦标赛树状图生成 PDF 文件,发放给参加三月疯狂竞赛的人。

安装 ReportLab

ReportLab 库可从 PyPI 获取。也可以下载 用户指南 (一份 PDF 文件,这不是巧合)。你可以用 pip 安装 ReportLab:

Linux/MacOS    Windows

  1. $ python -m pip install reportlab
  1. ...\> py -m pip install reportlab

在 Python 交互解释器中导入它,测试你的安装是否成功:

  1. >>> import reportlab

若该命令未抛出任何错误,安装成功。

编写视图

利用 Django 动态生成 PDF 的关键是 ReportLab API 作用于类文件对象,而 Django 的 FileResponse 对象接收类文件对象。

这有个 “Hello World” 示例:

  1. import io
  2. from django.http import FileResponse
  3. from reportlab.pdfgen import canvas
  4. def some_view(request):
  5. # Create a file-like buffer to receive PDF data.
  6. buffer = io.BytesIO()
  7. # Create the PDF object, using the buffer as its "file."
  8. p = canvas.Canvas(buffer)
  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. # FileResponse sets the Content-Disposition header so that browsers
  16. # present the option to save the file.
  17. buffer.seek(0)
  18. return FileResponse(buffer, as_attachment=True, filename='hello.pdf')

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

  • 响应会自动基于文件扩展名将 MIME 类型设置为应用程序 application/pdf。这告诉浏览器该文档是个 PDF 文件,而不是 HTML 文件或普通的应用程序 application/octet-stream 二进制内容。
  • as_attachment=True 传递给 FileResponse 时,它会设置合适的 Content-Disposition 头,这将告诉 Web 浏览器弹出一个对话框,提示或确认如何处理该文档,即便设备已配置默认行为。若省略了 as_attachment 参数,浏览器会用已配置的用于处理 PDF 的程序或插件来处理该 PDF。
  • 你也可以提供可选参数 filename。浏览器的“另存为…”对话框会用到它。
  • 你可以作为第一个参数传递给 canvas.Canvas 的缓冲区也能传递给类 FileResponse 类来使用 ReportLab API。
  • 注意,所有后续生成 PDF 的方法都是在 PDF 对象上调用的(本例中是 p)——而不是在 buffer 上调用。
  • 最后,牢记在 PDF 文件上调用 showPage()save()

注解

ReportLab 不是线程安全的。某些用户已经报告了一些奇怪的 issue,在创建用于生成 PDF 的 Django 视图时,这些视图被多个用户同时访问会出现问题。

其它格式

注意,这些例子中没有任何 PDF 特有的数据——只有使用 reportlab 的部分。你可以用类似的技巧生成任意格式,只要你能找到对应的 Python 库。也请看看 利用 Django 输出 CSV,看看另一个例子中,如何用一些技巧输出文本内容。

参见

Django 包提供了一个 包的比较 有助于用 Django 生成 PDF 文件。