El libro de Django 1.0

11.3. Generar PDFs

El Formato Portable de Documentos (PDF, por Portable Document Format) es un formato desarrollado por Adobe que es usado para representar documentos imprimibles, completos con formato perfecto hasta un nivel de detalle medido en pixels, tipografías empotradas y gráficos de vectores en 2D. Puedes pensar en un documento PDF como el equivalente digital de un documento impreso; efectivamente, los PDFs se usan normalmente cuando se necesita entregar un documento a alguien para que lo imprima.

Puedes generar PDFs fácilmente con Python y Django gracias a la excelente librería de software libre ReportLab. La ventaja de generar ficheros PDFs dinámicamente es que puedes crear PDFs a medida para diferentes propósitos — supongamos, para diferentes usuarios u diferentes contenidos.

Por ejemplo, hemos usado Django y ReportLab en KUSports.com para generar programas de torneos de la NCAA personalizados, listos para ser impresos.

11.3.1. Instalar ReportLab

Antes de que puedas generar ningún PDF, deberás instalar ReportLab. Este paso es muy sencillo, ya que solamente debes descargar la librería en el sitio reportlab.org/downloads.html.

La guía del usuario, que solamente está disponible en formato PDF, contiene instrucciones de instalación adicionales.

Nota Si estás usando una distribución moderna de Linux, podrías desear comprobar con la utilidad de manejo de paquetes de software antes de instalar ReportLab. La mayoría de los repositorios de paquetes ya incluyen ReportLab.

Por ejemplo, si estás usando la (excelente) distribución Ubuntu, un simple apt-get install python-reportlab hará la magia necesaria.

Prueba tu instalación importando la misma en el intérprete interactivo Python:

>>> import reportlab

Si ese comando no lanza ningún error, la instalación funcionó.

11.3.2. Escribir tu Vista

Del mismo modo que CSV, la generación de PDFs en forma dinámica con Django es sencilla porque la API ReportLab actúa sobre objetos similares a ficheros (file-like según la jerga Python).

A continuación un ejemplo "Hola Mundo":

from reportlab.pdfgen import canvas
from django.http import HttpResponse

def hello_pdf(request):
    # Create the HttpResponse object with the appropriate PDF headers.
    response = HttpResponse(mimetype='application/pdf')
    response['Content-Disposition'] = 'attachment; filename=hello.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

Son necesarias alguna notas:

  • Usamos el tipo MIME application/pdf. Esto le indica al navegador que el documento es un fichero PDF y no un fichero HTML. Si no incluyes esta información, los navegadores web probablemente interpretarán la respuesta como HTML, lo que resultará en jeroglíficos en la ventana del navegador.
  • Interactuar con la API ReportLab es sencillo: sólo pasa response como el primer argumento a canvas.Canvas. La clase Canvas espera un objeto file-like, y los objetos HttpResponse se ajustarán a la norma.
  • Todos los métodos de generación de PDF subsecuentes son llamados pasándoles el objeto PDF (en este caso p), no response.
  • Finalmente, es importante llamar a los métodos showPage() y save() del objeto PDF (de otra manera obtendrás un fichero PDF corrupto).

11.3.3. PDFs complejos

Si estás creando un documento PDF complejo (o cualquier pieza de datos de gran tamaño), considera usar la librería cStringIO como un lugar de almacenamiento temporario para tu fichero PDF. La librería cStringIO provee una interfaz vía objetos file-like que está escrita en C para máxima eficiencia.

Ese es el ejemplo "Hola Mundo" anterior modificado para usar cStringIO:

from cStringIO import StringIO
from reportlab.pdfgen import canvas
from django.http import HttpResponse

def hello_pdf(request):
    # Create the HttpResponse object with the appropriate PDF headers.
    response = HttpResponse(mimetype='application/pdf')
    response['Content-Disposition'] = 'attachment; filename=hello.pdf'

    temp = StringIO()

    # Create the PDF object, using the StringIO object as its "file."
    p = canvas.Canvas(temp)

    # 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.
    response.write(temp.getvalue())
    return response