20seven

Devigner blog about development and design

PDF Generation With PISA in Django

Today I had to come up with pdf generation for a project and was happy to find Pisa makes this cake-work. Pisa depends on Reportlab but you don’t have to dig into Reportlab to get your pdf generated.
h3. Setup

Go grab a copy of Pisa and if you don’t have Reportlab, grab that too while you’re at it. Install both then we’ll move on.

Nuts and Bolts

Create a standard html template for your view. Below is a sample of my template.


<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" 
    "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<style type="text/css">
	@page {
		size: ;
		margin: 1cm;
		@frame footer {
    		    -pdf-frame-content: footerblock;
    		    bottom: 1cm;
    		    margin-left: 1cm;
    		    margin-right: 1cm;
             margin-top: 1cm;
    		    height: 1cm;
		}
	}
</style>
</head>
<body>
<div>
    <h2></h2>
    <div></div>
</div>
<div id="footerblock">
    <pdf:pagenumber>
</div>
</body>
</html>

The template is pretty self-explanatory but the pager block will paginate your pdf.

For your view, do something like the following to create the pdf. The article function gets the article from the database and passes it on to write_pdf to generate the pdf from the html template we created earlier.


from django import http
from django.template.loader import get_template
from django.template import Context
import ho.pisa as pisa
import cStringIO as StringIO
import cgi

def write_pdf(template_src, context_dict):
    template = get_template(template_src)
    context = Context(context_dict)
    html  = template.render(context)
    result = StringIO.StringIO()
    pdf = pisa.pisaDocument(StringIO.StringIO(
        html.encode("UTF-8")), result)
    if not pdf.err:
        return http.HttpResponse(result.getvalue(), \
             mimetype='application/pdf')
    return http.HttpResponse('Gremlin's ate your pdf! %s' % cgi.escape(html))

def article(request, id):
    article = get_object_or_404(Article, pk=id)

    return write_pdf('dtd/pdf/template.html',{
        'pagesize' : 'A4',
        'article' : article})

[NOTE: I ran into issues with the prior encoding ISO-8859-1 where it blew up on quotations. UTF-8 is working better for me.]

A couple of things to point out here. Pagesize defaults to A4. From what i can tell this seems to be set in Reportlab not Pisa. write_pdf will get your template passing your context, encode it and serve up a nice little pdf for you.

Make it pretty with some css and background images and you’re set.
I took a look at the Reportlab api and see some cool canvas capabilities so I’m going to be hacking on that later in the week to try and generate pdf’s without the interim html step with complete graphical layouts.

Hopefully this helps someone needing pdf capabilities in their Django apps. It really is a Pisa cake. (bad pun intended)