網站在需要輸出 PDF 的時候,該怎麼辦呢?Python 不是有很多函式庫嗎?這些 PDF 函式庫能不能搭配 Django 來使用呢?
有喔,django-pdfkit 就是這樣的一個套件。
django-pdfkit 使用了 pdfkit 這個函式庫來輸出 PDF,而 pdfkit 又使用了 wkhtmltopdf 來將 HTML 轉為 PDF。講到這裡,沒錯,django-pdfkit 的內部運作是這樣的,先使用 Django 的 Template engine 輸出 HTML,再使用 wkhtmltopdf 將 HTML 轉為 PDF。
首先得安裝 wkhtmltopdf,在 ubuntu 裡,使用 apt-get 就可以安裝,但是,官方建議不要用 apt-get 安裝,而是下載二進位檔案來自行安裝。django-pdfkit 的套件網頁是這樣說的,wkhtmltopdf 網站的二進位檔案有修正過的 QT 函式庫以及更好的顯示支援,所以還是自行安裝吧。
# Linux
wget http://download.gna.org/wkhtmltopdf/0.12/0.12.3/wkhtmltox-0.12.3_linux-generic-amd64.tar.xz
tar -xf wkhtmltox-0.12.3_linux-generic-amd64.tar.xz
sudo cp -r wkhtmltox/* /usr/
# Mac / Homebrew
brew cask install wkhtmltopdf
接著,安裝套件
poetry add django-pdfkit
基本的用法很簡單,繼承 PDFView ,然後指定 template_name 就可以了。
下面我們就沿用前篇文章的 treemenu 來寫一個產出 PDF 的 View:
# treemenu/views.py
from django.views.generic import TemplateView
from django_pdfkit import PDFView
from .models import MenuItem
class TreePDFView(PDFView):
template_name = 'treemenu/treeview_pdf.html'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
rootmenu = MenuItem.objects.filter(parent__isnull=True).first()
context.update({
'rootmenu': rootmenu.get_descendants(),
})
return context
然後在 urlpatterns 加入這個新的 View
# urls.py
from treemenu.views import TreeView, TreePDFView
# ...
urlpatterns += [
# ...
path('tree.pdf/', TreePDFView.as_view()),
]
以及 template
# treemenu/templates/treemenu/treeview_pdf.html
{% load mptt_tags %}
<h1>PDF Demo</h1>
<ul>
{% recursetree rootmenu %}
<li>
{{ node.name }}
{% if not node.is_leaf_node %}
<ul class="children">
{{ children }}
</ul>
{% endif %}
</li>
{% endrecursetree %}
</ul>
用 runserver 啟動以後,就可以在瀏覽器網址列裡輸入 http://localhost:8000/tree.pdf/ ,按下 Enter 後,瀏覽器會出現對話視窗,要你選擇儲存檔案的位置。選擇好儲存檔案位置後,瀏覽器就會下載 PDF 了。
如果想要直接顯示在瀏覽器視窗,可以在網址列加上參數 inline: http://localhost:8000/tree.pdf/?inline= ,這樣就會直接顯示了。
除了 inline 以外,還有其他參數可以使用:
靠著 pdfkit 的威力,Django 也可以輸出 PDF,這樣要製作列印用報表,就沒什麼問題了。
範例程式網址:https://github.com/elleryq/ithome-iron-2020-django/tree/day-21