DjangoでgenericのDetailViewを使って日本語PDF出力をする方法です。
template htmlからPDFを出力したいのでxhtml2pdfというライブラリを使用します。
python3ではdevバージョンしか動かないので気をつけてください。
pip3 install --pre xhtml2pdf
まず使いたい日本語フォントを用意します。
次にフォントを<prj_name>/<prj_name>/static/fonts
に設置します。
設置したらsettings.pyにpathを通します。
prj_name/prj_name/settings.py
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, '<prj_name>', 'static')
次にviewを書いていきます。
今回は例としてfoo_app(<prj_name>/foos
)のモデルFoo
のDetailViewをPDFとして出力します。
generic.DetailView
を使いrender_to_response
の部分だけoverrideします。
prj_name/foos/views.py
import io
import os
from django.conf import settings
from django.views import generic
from django.http import HttpResponse
from django.template.loader import get_template
from xhtml2pdf import pisa
class FooPDFView(generic.DetailView):
model = Foo
template_name = 'foos/pdf.html'
def render_to_response(self, context):
html = get_template(self.template_name).render(self.get_context_data())
result = io.BytesIO()
pdf = pisa.pisaDocument(
io.BytesIO(html.encode('utf-8')),
result,
link_callback=link_callback,
encoding='utf-8',
)
if not pdf.err:
return HttpResponse(
result.getvalue(),
content_type='application/pdf'
)
return HttpResponse('<pre>%s</pre>' % escape(html))
def link_callback(uri, rel):
sUrl = settings.STATIC_URL
sRoot = settings.STATIC_ROOT
path = os.path.join(sRoot, uri.replace(sUrl, ""))
if not os.path.isfile(path):
raise Exception(
'%s must start with %s' % \
(uri, sUrl)
)
return path
templateを書いていきます。
フォントを設定しないと日本語は予期している通りに表示されないので気をつけてください。
prj_name/foos/templates/foos/pdf.html
<!DOCTYPE html>{% load static %}
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<style type="text/css">
@font-face {
font-family: "japanese";
src: url("{% static 'fonts/<your_font>.ttf' %}");
}
@page {
size: A4;
font-family: "japanese";
}
html, body {
font-family: "japanese";
}
</style>
</head>
<body>
<div>
名前 {{ object.name }}
</div>
</body>
</html>
urlsを設定します。
prj_name/foos/urls.py
app_name = 'foos'
urlpatterns = [
url(r'^(?P<pk>[0-9]+)/pdf/$',views.FooPDFView.as_view(), name='foo-pdf'),
]
projectのurlsに通します。
prj_name/prj_name/urls.py
urlpatterns = [
url(r'^foos/', include('foos.urls')),
]
これで/foos/:foo_id/pdfにアクセスするとPDFが出力されると思います。