LoginSignup
15
11

More than 5 years have passed since last update.

DjangoのDetailViewをPDFで出力する(日本語対応)

Last updated at Posted at 2017-07-11

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が出力されると思います。

15
11
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
15
11