How to create a PDF from HTML in Django

How to create a PDF from HTML in Django

Unlike PHP, there are not a lot of available libraries to create PDFs from HTML in Python, however it is not unsupported. In this article, you'll learn how to create PDFs using wkhtmltopdf in Django.

wkhtmltopdf is a command line tool to render HTML into PDF and various image formats using the Qt WebKit rendering engine. These run entirely "headless" and do not require a display or display service.

Requirements

You need wkhtmltopdf available in your system and accesible in the command prompt.

  • Windows: you can download an installer for each architecture (x86 and x64) in the installation area. Although you can change the path of the wkhtmltopdf executable later in the code, is recommendable to have wkhtmltopdf accesible as an environment variable on your system. You can read how to create environment variables in windows in this article.
  • Debian/Ubuntu: You can install the distribution from wkhtmltopdf directly in the console using the following command :
$ sudo apt-get install wkhtmltopdf

Warning! Version in debian/ubuntu repos have reduced functionality (because it compiled without the wkhtmltopdf QT patches), such as adding outlines, headers, footers, TOC etc. To use this options you should install static binary from wkhtmltopdf site or you can use this script.

Visit the homepage of wkhtmltopdf for more information here.

Implementation

Now that we have wkhtmltopdf available in our environment, we just need to use it ! however, instead of handling console commands by yourself, use PDFKit to create PDFs easily in Django. PDFKit is a python wrapper to convert html to pdf using the webkit rendering engine (wkhtmltopdf) and qt, you can visit the repository in Github for more information.

Include the PDFKit library into your django project using the following command :

$ pip install pdfkit

As wkhtmltopdf does the hard work for you, the use of PDFKit is really simple and cover almost all the use cases :

  • Create a PDF from a html string.
  • Create a PDF from a web url (external or project url).
#import pdfkit into your class
import pdfkit

# Generate PDF from a web URL (maybe only from your project)
pdfkit.from_url('http://google.com', 'out.pdf')
# Generate PDF from a html file.
pdfkit.from_file('file.html', 'out.pdf')
# Generate PDF from a plain html string.
pdfkit.from_string('Hello!', 'out.pdf')

# Save the PDF in a variable
myPdf = pdfkit.from_url('http://google.com', False)

And you are basically generating PDFs on the fly easily and quick.

Examples

It's easy to generate PDFs with Django and PDFKit, checkout the following examples:

Save PDF on the server

To save a PDF locally, use any method and provide the path and filename where the file should be saved as second parameter.

import pdfkit
from django.http import HttpResponse

def index(request):
    pdf = pdfkit.from_url("http://ourcodeworld.com", "ourcodeworld.pdf")

    return HttpResponse("Everything working good, check out the root of your project to see the generated PDF.")

The previous example will create a PDF in the root of your Django project.

Return PDF as response

You can retrieve directly a file from PDFKit without saving it in your system, just provide False as the destination parameter.

You can use the following snippet to return a PDF as response :

import pdfkit
from django.http import HttpResponse

def index(request):
    # Use False instead of output path to save pdf to a variable
    pdf = pdfkit.from_url('http://ourcodeworld.com', False)
    response = HttpResponse(pdf,content_type='application/pdf')
    response['Content-Disposition'] = 'attachment; filename="ourcodeworld.pdf"'

    return response

If you navigate to the route with this function, the browser will start to download the PDF generated by the controller.

Generate PDF from a project route

You can generate a PDF from a route (it need to be obviously registered) of your project and use the pdf.from_url method.

import pdfkit
from django.http import HttpResponse

def template(request):
    # Returns some HTML as response
    return HttpResponse("<h1>Hello World</h1>")

def pdf(request):

    # Create a URL of our project and go to the template route
    projectUrl = request.get_host() + '/template'
    pdf = pdfkit.from_url(projectUrl, False)
    # Generate download
    response = HttpResponse(pdf,content_type='application/pdf')
    response['Content-Disposition'] = 'attachment; filename="ourcodeworld.pdf"'

    return response

The pdf output will be a document with Hello World! as content.

Note: alternatively, instead of create a request to an endpoint of your project, you can render a template in a variable as html and then use the pdfkit.from_string method.

Other settings

Custom wkhtmltopdf path

If you want to modify the path where wkhtmltopdf is located, you can change it with the configuration method of pdfkit :

config = pdfkit.configuration(wkhtmltopdf='/opt/bin/wkhtmltopdf'))
pdfkit.from_string("<h1>Hello World</h1>", output_file, configuration=config)

PDF Settings

You can specify all wkhtmltopdf options. You can drop ‘–’ in option name. If option without value, use None, False or '' for dict value:

options = {
    'page-size': 'Letter',
    'margin-top': '0.75in',
    'margin-right': '0.75in',
    'margin-bottom': '0.75in',
    'margin-left': '0.75in',
    'encoding': "UTF-8",
    'no-outline': None
}

pdfkit.from_url('http://google.com', 'out.pdf', options=options)

wkhtmltopdf Output

By default, PDFKit will show all wkhtmltopdf output:

wkhtmltopdf output

If you dont want it, you need to set the quiet option in the configuration of the method that you use:

options = {
    'quiet': ''
}

pdfkit.from_url('google.com', 'out.pdf', options=options)

Basic troubleshooting

There are 2 know common issues while you use PDFKit in Python:

IOError - No wkhtmltopdf executable found

This error occurs because there's no wkhtmltopdf distribution in your system. In case that you've already installed, it's probably not available as a command in the console. Open your system console and verify if the wkhtmltopdf command exists.

IOError - Command Failed

Something went wrong with wkhtmltopdf and the operation couldn't be achieved. Try executing the plain command in the console and check for any possible error (the webpage doesn't exists, the file doesn't exists etc.).


Have fun !

Become a more social person