如何创建 PDF 文件¶
本文介绍如何用 Django 的视图动态输出 PDF 文件。该功能由绝佳的开源 ReportLab Python PDF 库提供。
动态生成 PDF 文件的优点是你可以为不同的目的创建不同的自定义 PDF——例如,为不同的用户或内容的不同片段生成 PDF。
例如,kusports.com 用 Django 将自定义的,打印友好的 NCAA 锦标赛树状图生成 PDF 文件,发放给参加三月疯狂竞赛的人。
安装 ReportLab¶
ReportLab 库可以在 PyPI 上获取。还可以下载 用户指南 (巧合的是,它是一个 PDF 文件)。你可以使用 pip
安装 ReportLab:
$ python -m pip install reportlab
...\> py -m pip install reportlab
通过在 Python 交互式解释器中导入它来测试您的安装:
>>> import reportlab
若该命令未抛出任何错误,安装成功。
编写视图¶
利用 Django 动态生成 PDF 的关键是 ReportLab API 作用于类文件对象,而 Django 的 FileResponse
对象接收类文件对象。
这有个 "Hello World" 示例:
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")
代码和注释应该是不言自明的,但是有几件事值得提一下:
- 响应会自动基于文件扩展名将 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 视图时,这些视图被多个用户同时访问会出现问题。