Django PDF 出力

1. 日本語対応フォントの印トール

日本語対応フォントを、staticディレクトリにインストールする

2. xhtml2pdf のインストール

pip install xmhtl2pdf

3.Viewの作成

Renderクラスを作成。このクラスをHTMLで作成されたデータを
xhml2pdfのpisaDocuemtクラスを使用しPDFへ変換する
処理を行うクラス。renderメソッドが処理で、リンク先のファイルを
読み込みをlink_callback 関数で定義している。

class Render:    @staticmethod    def render(path: str, params: dict):        template = get_template(path)        html = template.render(params)        response = BytesIO()        pdf = pisa.pisaDocument(BytesIO(html.encode("UTF-8")),                                response,                                encoding='utf-8',                                link_callback=Render.link_callback)        if not pdf.err:            return HttpResponse(response.getvalue(), content_type='application/pdf')        else:            return HttpResponse("Error Rendering PDF", status=400)    @staticmethod    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

注意
settings.pyはSTATIC_ROOTを追加しておく

STATIC_ROOT = os.path.join(BASE_DIR, 'static')

python manage.py collectstatic 実行しておく

4 View関数の作成

戻り値にRenderクラスのrenderを呼び出すように作成する

class Pdf(View):    def get(self, request):        orders = Order.objects.all()        today = timezone.now()        params = {            'today': today,            'orders': orders,            'request': request        }        return Render.render('pdf.html', params)_

URLの指定

urlpatterns = [    ・・・    path('render/pdf/', Pdf.as_view()),

5.テンプレートの作成

テンプレートファイルに日本語のフォントを指定し、作成する。

<!doctype html>{% load static %}<html><head>    <meta charset="utf-8">    <title>Sales Report</title>    <style type="text/css">         @font-face {            font-family: "japanese";            src: url("{% static 'ipam.ttf' %}");        }        @page {            size: A4;            margin: 1cm;            font-family: "japanese";        }        html, body {            font-family: "japanese";        }        .table {            width: 100%;            max-width: 100%;            margin-bottom: 5px;            background-color: #fff;        }        .table th,        .table td {            padding: 5px;            vertical-align: top;            border-top: 1px solid #000;            text-align: center;        }        .table thead th {            vertical-align: bottom;            border-bottom: 2px solid #000;        }        .table tbody + tbody {            border-top: 2px solid #000;        }        .table .table {            background-color: #fff;        }        .list-group {            display: block;            width: 100%;            list-style: none;            margin-top: 15px;            margin-bottom: 15px;        }        .list-group p {            width: 100%;            height: 20px;            line-height: 20px;            list-style: none;            font-size: 1.1em;        }    </style></head><body><div class="container">    <div class="card">        <div class="card-header">            <h3>Sales Report - {{ today | date:"d/m/Y" }}</h3>        </div>        <div class="list-group">            <p>Name: {{ request.user.first_name }} {{ request.user.last_name }}</p>        </div>        <table class="table">            <thead>            <tr>                <th>Date</th>                <th>Customer</th>                <th>Subject</th>                <th>Price</th>            </tr>            </thead>            <tbody>            {% for order in orders %}                <tr>                    <td>{{ order.created_at | date:"Y/m/d" }}</td>                    <td>{{ order.customer.name }}</td>                    <td>{{ order.subhect }}</td>                    <td>¥{{ order.price }}</td>                </tr>            {% endfor %}            </tbody>        </table>    </div></div></body></html>