Generating PDFs with Django

If your web app creates report chances are you also want this report in PDF form. The Django docs describe a way to generate PDFs using ReportLab. Here is some code from there.

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(mimetype='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

This suffers from two problems,

  1. You are laying out your PDF using Python, which means if you later want to change the design of the PDF you need to change the Python code.
  2. Most of the time you already have the report in Html, form, writing the same PDF via ReportLab is error prone.

Both these problems can be cleanly solved using Pisa, a Html2Pdf library. We proceed as,

  1. Generate a Html representation of Pdf using normal Django macienry.
  2. Convert to Pdf using Pisa.
  3. Return PDF.

This solves both our problems as,

  1. Designers can edit the template to change the layout of Pdf.
  2. The code to generate the Html and Pdf views can share code.

Here is some example code.

def html_view(request, as_pdf = False):
	#Get varaibles to populate the template
	payload = {'data':data, ....}
	if as_pdf:
		return payload
	return render_to_response('app/template.html', payload, RequestContext(request))

def pdf_view(request):
	payload = html_view(request, as_pdf = True)
	file_data = render_to_string('app/template.pdf', payload, RequestContext(request))
	myfile = StringIO.StringIO()
	pisa.CreatePDF(file_data, myfile)
	myfile.seek(0)
	response =  HttpResponse(myfile, mimetype='application/pdf')
	response['Content-Disposition'] = 'attachment; filename=coupon.pdf'
	return response

Thank you for reading the Agiliq blog. This article was written by shabda on Oct 7, 2008 in tips .

You can subscribe ⚛ to our blog.

We love building amazing apps for web and mobile for our clients. If you are looking for development help, contact us today ✉.

Would you like to download 10+ free Django and Python books? Get them here