這篇文檔闡述了如何通過使用Django視圖動(dòng)態(tài)輸出PDF。這可以通過一個(gè)出色的、開源的Python PDF庫(kù)ReportLab來(lái)實(shí)現(xiàn)。
動(dòng)態(tài)生成PDF文件的優(yōu)點(diǎn)是,你可以為不同目的創(chuàng)建自定義的PDF -- 這就是說,為不同的用戶或者不同的內(nèi)容。
例如,Django在kusports.com上用來(lái)為那些參加March Madness比賽的人,生成自定義的,便于打印的 NCAA 錦標(biāo)賽晉級(jí)表作為PDF文件。
ReportLab庫(kù)在PyPI上提供。也可以下載到用戶指南 (PDF文件,不是巧合)。 你可以使用pip
來(lái)安裝ReportLab:
$ pip install reportlab
通過在Python交互解釋器中導(dǎo)入它來(lái)測(cè)試你的安裝:
>>> import reportlab
若沒有拋出任何錯(cuò)誤,則已安裝成功。
使用Django動(dòng)態(tài)生成PDF的關(guān)鍵是,ReportLab API作用于類似于文件的對(duì)象,并且Django的 HttpResponse
對(duì)象就是類似于文件的對(duì)象。
這里是一個(gè) “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
代碼和注釋是不用多說的,但是一些事情需要提醒一下:
application/pdf
。這會(huì)告訴瀏覽器,文檔是個(gè)PDF文件而不是HTML文件。 如果你把它去掉,瀏覽器可能會(huì)把輸出解釋為HTML,會(huì)在瀏覽器窗口中顯示一篇丑陋的、可怕的官樣文章。Content-Disposition
協(xié)議頭,它含有PDF文件的名稱。 文件名可以是任意的;你想把它叫做什么都可以。瀏覽器會(huì)在”另存為“對(duì)話框中使用它,或者其它。Content-Disposition
協(xié)議頭以 'attachment;'
開頭。 這樣就強(qiáng)制讓瀏覽器彈出對(duì)話框來(lái)提示或者確認(rèn),如果機(jī)器上設(shè)置了默認(rèn)值要如何處理文檔。如果你去掉了'attachment;'
,無(wú)論什么程序或控件被設(shè)置為用于處理PDF,瀏覽器都會(huì)使用它。代碼就像這樣:response['Content-Disposition'] = 'filename="somefilename.pdf"'
canvas.Canvas
傳遞response
作為第一個(gè)參數(shù)。Canvas
函數(shù)接受一個(gè)類似于文件的對(duì)象,而 HttpResponse
對(duì)象正好合適。response
對(duì)象上。showPage()
和 save()
非常重要。注意
ReportLab并不是線程安全的。一些用戶報(bào)告了一些奇怪的問題,在構(gòu)建生成PDF的Django視圖時(shí)出現(xiàn),這些視圖在同一時(shí)間被很多人訪問。
如果你使用ReportLab創(chuàng)建復(fù)雜的PDF文檔,考慮使用io
庫(kù)作為你PDF文件的臨時(shí)保存地點(diǎn)。這個(gè)庫(kù)提供了一個(gè)類似于文件的對(duì)象接口,非常實(shí)用。這個(gè)是上面的“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
system
或者 popen
,在控制臺(tái)中使用它,然后再Python中取回輸出。要注意在這些例子中并沒有很多PDF特定的東西 -- 只是使用了reportlab
。你可以使用相似的技巧來(lái)生成任何格式,只要你可以找到對(duì)應(yīng)的Python庫(kù)。關(guān)于用于生成基于文本的格式的其它例子和技巧,另見使用Django輸出CSV。
譯者:Django 文檔協(xié)作翻譯小組,原文:Generating PDF。
本文以 CC BY-NC-SA 3.0 協(xié)議發(fā)布,轉(zhuǎn)載請(qǐng)保留作者署名和文章出處。
Django 文檔協(xié)作翻譯小組人手緊缺,有興趣的朋友可以加入我們,完全公益性質(zhì)。交流群:467338606。