Amazon.com Widgets
...not so private reflections of greg.newman
RSS feed - Categories & Search

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.

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>

</head>
<body>
<div>
    <h2>{{ article.articletitle|upper }}</h2>
    <div>{{ article.content }}</div>
</div>
<div id="footerblock">
{%block pager %}
    <pdf:pagenumber>
{%endblock%}
</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)

2 Comments

Thanks Greg! I've been looking for a cheaper version of Prince XML http://www.princexml.com/ for an ongoing commercial project.

This fits the bill exactly.

You're welcome Jachin. There's a lot of solutions based on ReportLab that fit the bill. This one by far is the easiest I've seen.

Leave a comment