Uno de los procesos más comunes realizados en programación es la generación y posterior salida de información, ya sea en formato texto u otros formatos. En este tutorial nos centraremos en la generación de PDFs con Python.
En este breve tutorial vamos a aprender como generar ficheros en formato PDF
con Python y para realizar esta tarea nos enfocaremos en el módulo de Python ReportLab
, una herramienta Open Source que pone a nuestra disposición gran variedad de opciones para realizar este proceso.
En los siguientes ejemplos utilizaremos clases y métodos haciendo uso de PLATYPUS
(Page Layout and Typography Using Scripts), que nos permite maquetar y presentar información en pocas líneas de código y sin comernos la cabeza. Forman parte del módulo de Python ReportLab que veremos a continuación.
Debemos saber que ReporLab necesita la librería PLATYPUS para funcionar, ya que es la encargada de configurar cada plantilla, marcos, cabeceras, párrafos, imágenes, gráficos, etc … Veamos a continuación de lo que es capaz de ofrecer PLATYPUS :
- DocTemplates es la plantilla del documento que queremos crear.
- PageTemplates es la plantilla para las diferentes páginas de nuestro documento.
- Frames son las capas que contendrán parte de la información en nuestros documento.
- Flowables son los elementos con los que maquetamos nuestro documento (párrafos, imágenes, gráficos, etc …).
- Canvas, nos permite diseñar o pintar en nuestro documento.
Instalación de ReportLab
Antes de comenzar, vamos a realizar unas comprobaciones previas para comprobar si tenemos instalado ReportLab.
1 2 3 4 5 6 7 8 |
Python 3.9.1 (default, Feb 25 2021, 18:16:06) Python 3.9.1 (default, Feb 25 2021, 18:16:06) [GCC 4.9.2] on linux Type "help", "copyright", "credits" or "license" for more information. >>> from reportlab.platypus import SimpleDocTemplate Traceback (most recent call last): File "<stdin>", line 1, in <module> ModuleNotFoundError: No module named 'reportlab' |
En nuestro caso no lo tenemos instalado, por lo que procedemos con su instalación a través del instalador de paquetes de Python Pip
.
1 |
# pip3 install reportlab |
1 2 3 4 5 6 7 8 |
$ pip install reportlab Defaulting to user installation because normal site-packages is not writeable Collecting reportlab Downloading reportlab-3.6.9-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (2.8 MB) ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 2.8/2.8 MB 24.0 MB/s eta 0:00:00 Requirement already satisfied: pillow>=4.0.0 in /usr/lib/python3/dist-packages (from reportlab) (9.0.1) Installing collected packages: reportlab Successfully installed reportlab-3.6.9 |
Debemos saber que que ReportLab sólo funciona correctamente en versiones 2.7+ y 3.6+ de Python, por lo que en otra versión no funcionará correctamente y es probable que se nos muestre el siguiente error durante su instalación:
1 2 3 4 5 6 7 8 |
Traceback (most recent call last): File "./test.py", line 3, in <module> from reportlab.platypus import SimpleDocTemplate File "/usr/local/lib/python3.4/dist-packages/reportlab/__init__.py", line 14, in <module> to remove this error.""" % (__min_python_version__)) ImportError: reportlab requires Python 2.7+ or 3.6+; other versions are unsupported. If you want to try with other python versions edit line 10 of reportlab/__init__ to remove this error. |
Si aún así queremos continuar tenemos que editar el fichero _init_ y en la línea 6 reemplazar la versión por la que estemos utilizando.
1 |
__min_python_version__ = (3,6) |
Por último podemos consultar que está instalado correctamente
1 2 |
$ pip freeze | grep reportlab reportlab==3.6.9 |
Creación de PDF
Para empezar vamos a utilizar la clase SimpleDocTemplate que es la que nos va a permitir construir nuestro documento PDF. Lo que hace SimpleDocTemplate es crear el objeto report, con la localización exacta del PDF que estamos creando. Por lo que una vez hemos hecho esto, nuestro objeto está listo para añadirle contenido.
1 2 |
from reportlab.platypus import SimpleDocTemplate report = SimpleDocTemplate("./tmp/report.pdf") |
A continuación vamos a asignarle un título, algo de texto, párrafos, imágenes y gráficos, pero para hacer esto necesitamos utilizar lo que ReportLab llama Flowables
. Los Flowables son partes del documento (párrafos, tablas, imágenes, etc …) que ReportLab utiliza para organizar y completar la creación de ficheros PDF.
1 |
from reportlab.platypus import Paragraph, Spacer, Table, Image |
Cada Flowable (Paragraph, Spacer, Table, Image) es una clase y las utilizamos para construir elementos individuales dentro documento. A continuación debemos indicarle a ReportLab que estilo queremos usar para cada parte del documento, por lo que vamos a necesitar importar más componentes del módulo para realizar esta tarea.
También podemos optar por crear nuestro propio estilo, pero en este ejemplo vamos a utilizar el estilo que trae por defecto el módulo. En este caso el objeto styles contiene el estilo por defecto “sample” y vamos a utilizar código HTML para poder representarlo. Empezamos utilizando un encabezado h1.
1 2 3 4 |
from reportlab.lib.styles import getSampleStyleSheet styles = getSampleStyleSheet() report_title = Paragraph("Mi lista de la compra", styles["h1"]) |
Para que el PDF pueda ser generado, tenemos que utilizar el método build().
1 |
report.build([report_title]) |
Nuestro script es muy básico y hasta ahora ha quedado así:
1 2 3 4 5 6 7 8 9 10 11 12 |
#! /usr/bin/env python3 from reportlab.platypus import SimpleDocTemplate report = SimpleDocTemplate("./tmp/report.pdf") from reportlab.platypus import Paragraph, Spacer, Table, Image # Estilos (por defecto el que trae reportlab) from reportlab.lib.styles import getSampleStyleSheet styles = getSampleStyleSheet() report_title = Paragraph("Mi lista de la compra", styles["h1"]) report.build([report_title]) |
Incluyendo Tablas
Hasta ahora, tan sólo hemos creado un documento PDF con un título, por lo que nuestro siguiente paso es incluir algo más de contenido. Disponemos de diccionario que contiene una lista de la compra con descripción y cantidad de lo que necesitamos.
1 |
list = { "leche": 5, "galletas": 2, "aceite": 3, "manzanas": 6, "queso": 1, "vino": 1, "cerveza": 2 } |
Vamos a crear una tabla con el contenido de la lista y para realizar esta tarea utilizaremos la clase Table para crear un objeto Table. Todos los datos incluidos en la lista los iremos incluyendo en un array de dos dimensiones. Veamos como realizar este proceso:
1 2 3 4 |
table_data = [] for k, v in list.items(): table_data.append([k, v]) print(table_data) |
Este proceso que acabamos de realizar se llama una lista de listas y procedemos a incluirla al reporte. A continuación volvemos a generar el PDF llamando al método build(), indicando el título y la tabla que queremos incluir.
1 2 |
report_table = Table(data=table_data) report.build([report_title, report_table]) |
Parece funcionar pero visualmente se ve horrible, por lo que vamos a incluir alineaciones y algo de estilo para que sea más agradable a la vista. Empezaremos por alinear la tabla y crear un borde en sus celdas. Como siempre digo, es recomendable revisar la documentación para saber cómo realizar esta tarea:
1 2 3 4 |
from reportlab.lib import colors table_style = [('GRID', (0,0), (-1,-1), 1, colors.black)] report_table = Table(data=table_data, style=table_style, hAlign="LEFT") report.build([report_title, report_table]) |
Hasta ahora nuestro script es el siguiente:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
#! /usr/bin/env python3 from reportlab.platypus import SimpleDocTemplate report = SimpleDocTemplate("./tmp/report.pdf") from reportlab.platypus import Paragraph, Spacer, Table, Image # Estilos (por defecto el que trae reportlab) from reportlab.lib.styles import getSampleStyleSheet styles = getSampleStyleSheet() # otros módulos from reportlab.lib import colors # título del documento report_title = Paragraph("Mi lista de la compra", styles["h1"]) # Nuestra lista de la compra list = { "leche": 5, "galletas": 2, "aceite": 3, "manzanas": 6, "queso": 1, "vino": 1, "cerveza": 2 } # generando la lista de listas table_data = [] for k, v in list.items(): table_data.append([k, v]) # borde de tabla y alineación table_style = [('GRID', (0,0), (-1,-1), 1, colors.black)] report_table = Table(data=table_data, style=table_style, hAlign="LEFT") # generamos el pdf report.build([report_title, report_table]) |
Incluyendo Gráficas
Hasta ahora nuestro documento PDF, se compone de un título y una tabla, por lo que el siguiente paso es aprender a incluir algunas gráficas. Vamos a incluir un gráfico circular (en inglés llamado Pie Chart) y para poder hacerlo necesitamos hacer uso de la clase Drawing que se encarga de generar todo este tipo de gráficas.
1 2 |
from reportlab.graphics.shapes import Drawing from reportlab.graphics.charts.piecharts import Pie |
Para incluir datos a nuestro gráfico circular necesitamos incluir dos listas por separado:
- La primera lista contiene las etiquetas (labels)
- La segunda lista es la que contendrá los datos (data).
1 2 3 4 5 6 7 8 9 10 11 12 13 |
from reportlab.graphics.shapes import Drawing from reportlab.graphics.charts.piecharts import Pie inch = 1 report_pie = Pie(width=3*inch, height=3*inch) report_pie.data = [] report_pie.labels = [] for producto in sorted(list): report_pie.data.append(list[producto]) report_pie.labels.append(producto) print(report_pie.data) # [3, 2, 2, 5, 6, 1, 1] print(report_pie.labels) # ['aceite', 'cerveza', 'galletas', 'leche', 'manzanas', 'queso', 'vino'] |
El siguiente paso es crear el gráfico y agregar cada lista (etiquetas y datos).
1 2 |
report_chart = Drawing() report_chart.add(report_pie) |
Por último lo incluimos en el reporte a la hora de construir el PDF:
1 |
report.build([report_title, report_table, report_chart]) |
El script completo es el siguiente:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
#! /usr/bin/env python3 from reportlab.platypus import SimpleDocTemplate report = SimpleDocTemplate("./tmp/report.pdf") from reportlab.platypus import Paragraph, Spacer, Table, Image # Estilos (por defecto el que trae reportlab) from reportlab.lib.styles import getSampleStyleSheet styles = getSampleStyleSheet() # Colores from reportlab.lib import colors # Gráficas from reportlab.graphics.shapes import Drawing from reportlab.graphics.charts.piecharts import Pie # título del documento report_title = Paragraph("Mi lista de la compra", styles["h1"]) # Nuestra lista de la compra list = { "leche": 5, "galletas": 2, "aceite": 3, "manzanas": 6, "queso": 1, "vino": 1, "cerveza": 2 } # generando la lista de listas table_data = [] for k, v in list.items(): table_data.append([k, v]) # borde de tabla y alineación table_style = [('GRID', (0,0), (-1,-1), 1, colors.black)] report_table = Table(data=table_data, style=table_style, hAlign="LEFT") # generando gráficas inch = 1 report_pie = Pie(width=3*inch, height=3*inch) report_pie.data = [] report_pie.labels = [] for producto in sorted(list): report_pie.data.append(list[producto]) report_pie.labels.append(producto) #print(report_pie.data) # [3, 2, 2, 5, 6, 1, 1] #print(report_pie.labels) # ['aceite', 'cerveza', 'galletas', 'leche', 'manzanas', 'queso', 'vino'] report_chart = Drawing() report_chart.add(report_pie) # generamos el pdf report.build([report_title, report_table, report_chart]) |
Y el resultado final sería algo parecido a esto:
Podemos consultar toda la documentación Oficial de ReportLab siguiendo este enlace. o descargar su guía oficial en formato PDF.