The key to generating PDFs dynamically with Django is that the ReportLab API
acts on file-like objects, and Django’s HttpResponse
objects are file-like objects.

Here’s a “Hello World” example:

fromreportlab.pdfgenimportcanvasfromdjango.httpimportHttpResponsedefsome_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()returnresponse

The code and comments should be self-explanatory, but a few things deserve a
mention:

The response gets a special MIME type, application/pdf. This
tells browsers that the document is a PDF file, rather than an HTML file.
If you leave this off, browsers will probably interpret the output as
HTML, which would result in ugly, scary gobbledygook in the browser
window.

The response gets an additional Content-Disposition header, which
contains the name of the PDF file. This filename is arbitrary: Call it
whatever you want. It’ll be used by browsers in the “Save as...”
dialogue, etc.

The Content-Disposition header starts with 'attachment;' in this
example. This forces Web browsers to pop-up a dialog box
prompting/confirming how to handle the document even if a default is set
on the machine. If you leave off 'attachment;', browsers will handle
the PDF using whatever program/plugin they’ve been configured to use for
PDFs. 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 the
first argument to canvas.Canvas. The Canvas class expects a
file-like object, and HttpResponse objects fit the
bill.

Note that all subsequent PDF-generation methods are called on the PDF
object (in this case, p) – not on response.

Finally, it’s important to call showPage() and save() on the PDF
file.

If you’re creating a complex PDF document with ReportLab, consider using the
cStringIO library as a temporary holding place for your PDF file. This
library provides a file-like object interface that is particularly efficient.
Here’s the above “Hello World” example rewritten to use cStringIO:

# Fall back to StringIO in environments where cStringIO is not availabletry:fromcStringIOimportStringIOexceptImportError:fromStringIOimportStringIOfromreportlab.pdfgenimportcanvasfromdjango.httpimportHttpResponsedefsome_view(request):# Create the HttpResponse object with the appropriate PDF headers.response=HttpResponse(mimetype='application/pdf')response['Content-Disposition']='attachment; filename="somefilename.pdf"'buffer=StringIO()# Create the PDF object, using the StringIO 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 StringIO buffer and write it to the response.pdf=buffer.getvalue()buffer.close()response.write(pdf)returnresponse

Notice that there isn’t a lot in these examples that’s PDF-specific – just the
bits using reportlab. You can use a similar technique to generate any
arbitrary format that you can find a Python library for. Also see
Outputting CSV with Django for another example and some techniques you can use
when generated text-based formats.