【Django(コピペ可)】html を pdf に変換する

※本サイトにはプロモーション・広告が含まれています。

本日は、Djangoにて、

htmlをpdfへ変換し、ダウンロードする

方法を公開します

現時点(2021年3月29日)で試したところ、うまく行きましたので参考になれば幸いです

また、こちらのドキュメントを参考にしてますので、英語でも問題ない!という方は一緒に読み進めることをお勧めします!

筆者プロフィール

筆者プロフィールアイコン

【現職】プロダクトマネージャー

【副業】ブログ(月間20万PV)/YouTube/Web・アプリ制作

「プログラミング × ライティング × 営業」の経験を活かし、30後半からのIT系職へシフト。現在はプロダクトマネージャーとして、さまざまな関係者の間に入り奮闘してます。当サイトでは、実際に手を動かせるWebアプリの開発を通じて、プログラミングはもちろん、IT職に必要な情報を提供していきます。

【当ブログで紹介しているサイト】

当サイトチュートリアルで作成したデモ版日報アプリ

Django × Reactで開発したツール系Webアプリ

✔人に見せても恥ずかしくないコードを書こう

「リーダブルコード」は、わかりやすく良いコードの定義を教えてくれる本です。

  • 見るからにきれいなコードの書き方
  • コードの分割方法
  • 変数や関数の命名規則

エンジニアのスタンダートとすべき基準を一から解説しています。

何回も読むのに値する本なので、ぜひ手にとって読んでみてください。

はじめに

今回は簡易的な、請求書フォームのようなものを作っています

本当に簡易的なものですので、下記を読んでやり方を覚えたらカスタマイズしてください!

【views.py】

import os
from django.conf import settings
from django.http import HttpResponse
from django.template.loader import get_template
from xhtml2pdf import pisa
from django.contrib.staticfiles import finders

import datetime

def link_callback(uri, rel):
        result = finders.find(uri)
        if result:
                if not isinstance(result, (list, tuple)):
                        result = [result]
                result = list(os.path.realpath(path) for path in result)
                path=result[0]
        else:
                sUrl = settings.STATIC_URL        
                sRoot = settings.STATIC_ROOT      
                mUrl = settings.MEDIA_URL         
                mRoot = settings.MEDIA_ROOT       

                if uri.startswith(mUrl):
                        path = os.path.join(mRoot, uri.replace(mUrl, ""))
                elif uri.startswith(sUrl):
                        path = os.path.join(sRoot, uri.replace(sUrl, ""))
                else:
                        return uri

        if not os.path.isfile(path):
                raise Exception(
                        'media URI must start with %s or %s' % (sUrl, mUrl)
                )
        return path

def render_pdf_view(request):
    template_path = 'realestate/invoice.html' #ここにはテンプレートの場所を入れる

#ここがテンプレート内にレンダーされるcontextになります
    context = {'title': 'Invoice',
               'today': datetime.date.today(), 
               'amount': 39.99,
               'customer_name': 'Yulikepython',
               'order_id': 1233434,
    }

    response = HttpResponse(content_type='application/pdf')
    response['Content-Disposition'] = 'attachment; filename="report.pdf"'

    template = get_template(template_path)
    html = template.render(context)

    pisa_status = pisa.CreatePDF(
       html, dest=response, link_callback=link_callback)

    if pisa_status.err:
       return HttpResponse('We had some errors <pre>' + html + '</pre>')
    return response

基本はコピペで大丈夫かと思います

変更すべき点は主に2箇所

  1. template_path
  2. context

になります!

【テンプレート】

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
    <head>
        <title>Title</title>
        <style type="text/css">
            body {
                font-weight: 200;
                font-size: 14px;
                font-family: HeiseiMin-W3;
            }
            .header {
                font-size: 20px;
                font-weight: 100;
                text-align: center;
                color: #007cae;
            }
            .title {
                font-size: 22px;
                font-weight: 100;
               /* text-align: right;*/
               padding: 10px 20px 0px 20px;  
            }
            .title span {
                color: #007cae;
            }
            .details {
                padding: 10px 20px 0px 20px;
                text-align: left !important;
                /*margin-left: 40%;*/
            }
            .hrItem {
                border: none;
                height: 1px;
                /* Set the hr color */
                color: #333; /* old IE */
                background-color: #fff; /* Modern Browsers */
            }
        </style>
    </head>
    <body>
        <div class='wrapper'>
            <div class='header'>
                <p class='title'>Invoice #{{ order_id }} </p>
            </div>
        <div>
        <div class='details'>
            Title: {{title}}<br /> 
            Bill to: {{ customer_name }}<br/>
            Amount:  {{ amount }}<br/>
            Date: {{today}}
            <hr class='hrItem' />
        </div>
    </div>
    </body>
</html>

ポイントとしては、

font-familyをHeiseiMin-W3

にすることで日本語が文字化けしなくなります

また、styleを同ページで記述していること

別ファイルのcssを読み込んでもできるかどうかは試していませんので、興味のある方は試してみて下さい!

そしてできたら教えて下さい!!

【urls.py】

from .views import (
     .,
                      .,
                      render_pdf_view,
                    )

urlspattern = [
    path("generate-pdf/", render_pdf_view, name="generate_pdf"),
]

あとは、urls.pyで指定したアドレスへGO!!

タイトルとURLをコピーしました