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