{% raw %}
# 使用Django輸出PDF #
這篇文檔闡述了如何通過使用Django視圖動態輸出PDF。這可以通過一個出色的、開源的Python PDF庫[ReportLab](http://www.reportlab.com/opensource/)來實現。
動態生成PDF文件的優點是,你可以為不同目的創建自定義的PDF -- 這就是說,為不同的用戶或者不同的內容。
例如,Django在[kusports.com](http://www.kusports.com/)上用來為那些參加March Madness比賽的人,生成自定義的,便于打印的 NCAA 錦標賽晉級表作為PDF文件。
## 安裝ReportLab ##
ReportLab庫在[PyPI](https://pypi.python.org/pypi/reportlab)上提供。也可以下載到[用戶指南](http://www.reportlab.com/docs/reportlab-userguide.pdf) (PDF文件,不是巧合)。 你可以使用`pip`來安裝ReportLab:
```
$ pip install reportlab
```
通過在Python交互解釋器中導入它來測試你的安裝:
```
>>> import reportlab
```
若沒有拋出任何錯誤,則已安裝成功。
## 編寫你的視圖 ##
使用Django動態生成PDF的關鍵是,ReportLab API作用于類似于文件的對象,并且Django的 `HttpResponse`對象就是類似于文件的對象。
這里是一個 “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
```
代碼和注釋是不用多說的,但是一些事情需要提醒一下:
+ 響應對象獲得了一個特殊的MIME類型, `application/pdf`。這會告訴瀏覽器,文檔是個PDF文件而不是HTML文件。 如果你把它去掉,瀏覽器可能會把輸出解釋為HTML,會在瀏覽器窗口中顯示一篇丑陋的、可怕的官樣文章。
+ 響應對象獲取了附加的`Content-Disposition`協議頭,它含有PDF文件的名稱。 文件名可以是任意的;你想把它叫做什么都可以。瀏覽器會在”另存為“對話框中使用它,或者其它。
+ 在這個例子中,`Content-Disposition` 協議頭以 `'attachment;'` 開頭。 這樣就強制讓瀏覽器彈出對話框來提示或者確認,如果機器上設置了默認值要如何處理文檔。如果你去掉了`'attachment;'`,無論什么程序或控件被設置為用于處理PDF,瀏覽器都會使用它。代碼就像這樣:
```
response['Content-Disposition'] = 'filename="somefilename.pdf"'
```
+ 鉤住ReportLab API 非常簡單:只需要向`canvas.Canvas`傳遞`response`作為第一個參數。`Canvas`函數接受一個類似于文件的對象,而 `HttpResponse`對象正好合適。
+ 注意所有隨后的PDF生成方法都在PDF對象(這個例子是p)上調用,而不是`response`對象上。
+ 最后,在PDF文件上調用`showPage()` 和 `save()`非常重要。
> 注意
>
> ReportLab并不是線程安全的。一些用戶報告了一些奇怪的問題,在構建生成PDF的Django視圖時出現,這些視圖在同一時間被很多人訪問。
## 復雜的PDF ##
如果你使用ReportLab創建復雜的PDF文檔,考慮使用`io`庫作為你PDF文件的臨時保存地點。這個庫提供了一個類似于文件的對象接口,非常實用。這個是上面的“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
```
## 更多資源 ##
+ [PDFlib](http://www.pdflib.org/)與Python捆綁的另一個PDF生成庫。在Django中使用它的方法和這篇文章所闡述的相同。
+ [Pisa XHTML2PDF](http://www.xhtml2pdf.com/)是另一個PDF生成庫。Pisa自帶了如何將 Pisa 集成到 Django的例子。
+ [HTMLdoc](http://www.htmldoc.org/)是一個命令行腳本,它可以把HTML轉換為PDF。它并沒有Python接口,但是你可以使用`system` 或者 `popen`,在控制臺中使用它,然后再Python中取回輸出。
## 其它格式 ##
要注意在這些例子中并沒有很多PDF特定的東西 -- 只是使用了`reportlab`。你可以使用相似的技巧來生成任何格式,只要你可以找到對應的Python庫。關于用于生成基于文本的格式的其它例子和技巧,另見[使用Django輸出CSV](http://python.usyiyi.cn/django/howto/outputting-csv.html)。
> 譯者:[Django 文檔協作翻譯小組](http://python.usyiyi.cn/django/index.html),原文:[Generating PDF](https://docs.djangoproject.com/en/1.8/howto/outputting-pdf/)。
>
> 本文以 [CC BY-NC-SA 3.0](http://creativecommons.org/licenses/by-nc-sa/3.0/cn/) 協議發布,轉載請保留作者署名和文章出處。
>
> [Django 文檔協作翻譯小組](http://python.usyiyi.cn/django/index.html)人手緊缺,有興趣的朋友可以加入我們,完全公益性質。交流群:467338606。
{% endraw %}
- 新手入門
- 從零開始
- 概覽
- 安裝
- 教程
- 第1部分:模型
- 第2部分:管理站點
- 第3部分:視圖和模板
- 第4部分:表單和通用視圖
- 第5部分:測試
- 第6部分:靜態文件
- 高級教程
- 如何編寫可重用的應用
- 為Django編寫首個補丁
- 模型層
- 模型
- 模型語法
- 元選項
- 模型類
- 查詢集
- 執行查詢
- 查找表達式
- 模型的實例
- 實例方法
- 訪問關聯對象
- 遷移
- 模式編輯器
- 編寫遷移
- 高級
- 管理器
- 原始的SQL查詢
- 聚合
- 多數據庫
- 自定義查找
- 條件表達式
- 數據庫函數
- 其它
- 遺留的數據庫
- 提供初始數據
- 優化數據庫訪問
- 視圖層
- 基礎
- URL配置
- 視圖函數
- 快捷函數
- 裝飾器
- 參考
- 內建的視圖
- TemplateResponse 對象
- 文件上傳
- 概覽
- File 對象
- 儲存API
- 管理文件
- 自定義存儲
- 基于類的視圖
- 概覽
- 內建顯示視圖
- 內建編輯視圖
- API參考
- 分類索引
- 高級
- 生成 CSV
- 生成 PDF
- 中間件
- 概覽
- 內建的中間件類
- 模板層
- 基礎
- 面向設計師
- 語言概覽
- 人性化
- 面向程序員
- 表單
- 基礎
- 概覽
- 表單API
- 內建的Widget
- 高級
- 整合媒體
- 開發過程
- 設置
- 概覽
- 應用程序
- 異常
- 概覽
- django-admin 和 manage.py
- 添加自定義的命令
- 測試
- 介紹
- 部署
- 概述
- WSGI服務器
- 部署靜態文件
- 通過email追蹤代碼錯誤
- Admin
- 管理操作
- 管理文檔生成器
- 安全
- 安全概述
- 說明Django中的安全問題
- 點擊劫持保護
- 加密簽名
- 國際化和本地化
- 概述
- 本地化WEB UI格式化輸入
- “本地特色”
- 常見的網站應用工具
- 認證
- 概覽
- 使用認證系統
- 密碼管理
- 日志
- 分頁
- 會話
- 數據驗證
- 其它核心功能
- 按需內容處理
- 重定向
- 信號
- 系統檢查框架