HTML to PDF in Django

#StandWithUkraine
Today, 4th December 2022, Ukraine is still bravely fighting for democratic values, human rights and peace in whole world. Russians ruthlessly kill all civilians in Ukraine including childs and destroy their cities. We are uniting against Putinโ€™s invasion and violence, in support of the people in Ukraine. You can help by donating to Ukrainian's army.

Install pdfkit:

pip install pdfkit

pdfkit uses wkhtmltopdf binary so we also need to install it. If you run Ubuntu do:

sudo apt-get install wkhtmltopdf

If you run Windows get binary here: http://wkhtmltopdf.org/downloads.html . You need to add path to wkhtmltopdf.exe into PATH variable. E.g. if you use default install path you have to add c:\Program Files\wkhtmltopdf\bin\. Restart programs that will run your app (e.g. IDE) to apply changes in PATH.

Now, in Django you can create the next view:

def export_to_pdf(request, tip_id):
    options = {
        'page-size': 'A4',
        'margin-top': '0.55in',
        'margin-right': '0.55in',
        'margin-bottom': '0.55in',
        'margin-left': '0.55in',
        'encoding': "UTF-8",
        # any other wkhtmltopdf options
    }
    
    content = render_to_string(
        'pdf_template.html', {
            'contents': some_your_html
        }
    )
    
    pdf = pdfkit.PDFKit(content, "string", options=options).to_pdf()
    
    response = HttpResponse(pdf)
    response['Content-Type'] = 'application/pdf'
    # change attachment to inline if you want open file in browser tab instead downloading
    response['Content-disposition'] = 'attachment;filename={}.pdf'.format(your_filename)
    
    return response

Create HTML template. Example:

<!DOCTYPE html>
<html>
<head>
    <title>Some title here</title>
    <style type="text/css">
    <!-- if you need style use: -->
    {% include  "some_your_style_that_you_need.css" %}
    
    </style>
</head>
<body>
    {{ contents | safe }}
</body>
</html>

If you want style like in example above you need add path to your some_your_style_that_you_need.css into TEMPLATES 'DIRS' setting in settings.py

If you want to add images from your server you can use path to file on server instead web URLs, e.g. <img src="/srv/www/server.jpg" >

Solving problem with required X server for version < 0.12.2.1

One drawback of this method is that Versions of wkhtmltopdf < 0.12.2.1 need X server. If you can't or don't want install newer version, but need to run headless on servers where there is no X server, you can easily emulate it with xvfb:

apt-get install xvfb

Create file named wkhtmltopdf_xfaked.sh in your Django project base dir - near manage.py (e.g. using vim or nano) and add there:

#!/bin/bash
xvfb-run -a -s "-screen 0 1024x768x24" wkhtmltopdf $*

Add executable permission to script:

chmod +x wkhtmltopdf_xfaked.sh

Then we need to force pdfkit to use our wkhtmltopdf_xfaked.sh instead of default binary:

if settings.PRODUCTION:
    # on production we have no X server, that needed for wkhtmltopdf, so we will emulate it and so we need to use custom path to wkhtmltopdf executable
    config = pdfkit.configuration(wkhtmltopdf=os.path.join(settings.BASE_DIR, 'wkhtmltopdf_xfaked.sh').encode())
    pdf = pdfkit.PDFKit(content, "string", options=options, configuration=config).to_pdf()
else:
    # on dev machine I use Windows so it is no need to emulate X sereve and redefine path
    pdf = pdfkit.PDFKit(content, "string", options=options).to_pdf()

Also if you need some extra fonts to support, e.g monospaced you can also install:

mkfontdir
sudo apt-get install xfonts-100dpi xfonts-75dpi xfonts-cyrillic
sudo apt-get install ttf-mscorefonts-installer

(Need to accept EULA in the installer)

#html #pdf
0
Ivan Borshchov profile picture
Dec 03, 2016
by Ivan Borshchov
Did it help you?
Yes !
No

Best related