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 accessible 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! The 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 these 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:
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 !