Outputting PDFs with Django
This document explains how to output PDF files dynamically using Django views.This is made possible by the excellent, open-source ReportLab Python PDFlibrary.
The advantage of generating PDF files dynamically is that you can createcustomized PDFs for different purposes — say, for different users or differentpieces of content.
For example, Django was used at kusports.com to generate customized,printer-friendly NCAA tournament brackets, as PDF files, for peopleparticipating in a March Madness contest.
Install ReportLab
The ReportLab library is available on PyPI. A user guide (notcoincidentally, a PDF file) is also available for download.You can install ReportLab with pip
:
- $ pip install reportlab
Test your installation by importing it in the Python interactive interpreter:
- >>> import reportlab
If that command doesn't raise any errors, the installation worked.
Write your view
The key to generating PDFs dynamically with Django is that the ReportLab APIacts on file-like objects, and Django's HttpResponse
objects are file-like objects.
Here's a "Hello World" example:
- from django.http import HttpResponse
- from reportlab.pdfgen import canvas
- def some_view(request):
- # Create the HttpResponse object with the appropriate PDF headers.
- response = HttpResponse(content_type='application/pdf')
- response['Content-Disposition'] = 'attachment; filename="somefilename.pdf"'
- # Create the PDF object, using the response object as its "file."
- p = canvas.Canvas(response)
- # Draw things on the PDF. Here's where the PDF generation happens.
- # See the ReportLab documentation for the full list of functionality.
- p.drawString(100, 100, "Hello world.")
- # Close the PDF object cleanly, and we're done.
- p.showPage()
- p.save()
- return response
The code and comments should be self-explanatory, but a few things deserve amention:
The response gets a special MIME type, application/pdf. Thistells browsers that the document is a PDF file, rather than an HTML file.If you leave this off, browsers will probably interpret the output asHTML, which would result in ugly, scary gobbledygook in the browserwindow.
The response gets an additional
Content-Disposition
header, whichcontains the name of the PDF file. This filename is arbitrary: Call itwhatever you want. It'll be used by browsers in the "Save as…" dialog, etc.The
Content-Disposition
header starts with'attachment; '
in thisexample. This forces Web browsers to pop-up a dialog boxprompting/confirming how to handle the document even if a default is seton the machine. If you leave off'attachment;'
, browsers will handlethe PDF using whatever program/plugin they've been configured to use forPDFs. Here's what that code would look like:
- response['Content-Disposition'] = 'filename="somefilename.pdf"'
Hooking into the ReportLab API is easy: Just pass
response
as thefirst argument tocanvas.Canvas
. TheCanvas
class expects afile-like object, andHttpResponse
objects fit thebill.Note that all subsequent PDF-generation methods are called on the PDFobject (in this case,
p
) — not onresponse
.Finally, it's important to call
showPage()
andsave()
on the PDFfile.
Note
ReportLab is not thread-safe. Some of our users have reported odd issueswith building PDF-generating Django views that are accessed by many peopleat the same time.
Complex PDFs
If you're creating a complex PDF document with ReportLab, consider using theio
library as a temporary holding place for your PDF file. Thislibrary provides a file-like object interface that is particularly efficient.Here's the above "Hello World" example rewritten to use io
:
- from io import BytesIO
- from reportlab.pdfgen import canvas
- from django.http import HttpResponse
- def some_view(request):
- # Create the HttpResponse object with the appropriate PDF headers.
- response = HttpResponse(content_type='application/pdf')
- response['Content-Disposition'] = 'attachment; filename="somefilename.pdf"'
- buffer = BytesIO()
- # Create the PDF object, using the BytesIO object as its "file."
- p = canvas.Canvas(buffer)
- # Draw things on the PDF. Here's where the PDF generation happens.
- # See the ReportLab documentation for the full list of functionality.
- p.drawString(100, 100, "Hello world.")
- # Close the PDF object cleanly.
- p.showPage()
- p.save()
- # Get the value of the BytesIO buffer and write it to the response.
- pdf = buffer.getvalue()
- buffer.close()
- response.write(pdf)
- return response
Other formats
Notice that there isn't a lot in these examples that's PDF-specific — just thebits using reportlab
. You can use a similar technique to generate anyarbitrary format that you can find a Python library for. Also seeOutputting CSV with Django for another example and some techniques you can usewhen generated text-based formats.
See also
Django Packages provides a comparison of packages that help generate PDF filesfrom Django.