En este pequeño tutorial, voy a presentar como realizar un reporte en pdf utilizando ReportLab en Django, para ello vamos a empezar describiendo un pequeño caso de uso muy común en muchos proyectos, que es obtener un listado en forma de tabla de los registros de una base de datos.
Supongamos que tenemos una tabla Persona con los siguientes campos:
from django.db import models class Persona(models.Model): apellido = models.CharField( max_length=50 ) nombre = models.CharField( max_length=50 ) dni = models.PositiveIntegerField() telefono = models.CharField( max_length=25 ) email = models.EmailField( max_length=75 )
Guiándonos de la documentación oficial de Django creamos la siguiente vista la cual llama al método run de la clase ReportePersonas que es la que contiene la lógica que devuelve como respuesta a nuestra petición el archivo pdf.
Esta vista le asigna la directiva 'application/pdf' al objeto response que le indica al navegador que es un archivo pdf y el header 'Content-Disposition' con el nombre de tal.
from django.shortcuts import render from django.http import HttpResponse from .models import Persona from .reportes import ReportePersona def reporte_personas(request): response = HttpResponse(content_type='application/pdf') response['Content-Disposition'] = 'attachment; filename="personas.pdf"' r = ReportePersona() response.write(r.run()) return response
A continuación se describe la clase que genera el reporte en pdf:
from io import BytesIO from reportlab.lib.pagesizes import A4 from reportlab.lib.styles import ParagraphStyle, TA_CENTER from reportlab.lib.units import inch, mm from reportlab.lib import colors from reportlab.platypus import ( Paragraph, Table, SimpleDocTemplate, Spacer, TableStyle, Paragraph) from .models import Persona class ReportePersona(object): def __init__(self): self.buf = BytesIO() def run(self): self.doc = SimpleDocTemplate(self.buf) self.story = [] self.encabezado() self.crearTabla() self.doc.build(self.story, onFirstPage=self.numeroPagina, onLaterPages=self.numeroPagina) pdf = self.buf.getvalue() self.buf.close() return pdf def encabezado(self): p = Paragraph("Reporte Personas", self.estiloPC()) self.story.append(p) self.story.append(Spacer(1,0.5*inch)) def crearTabla(self): data = [["Apellido","Nombre","DNI","Telefono","email"]] \ +[[x.apellido, x.nombre, x.dni, x.telefono, x.email] for x in Persona.objects.all()] style = TableStyle([ ('GRID', (0,0), (-1,-1), 0.25, colors.black), ('ALIGN',(0,0),(-1,-1),'CENTER'), ('VALIGN',(0,0),(-1,-1),'MIDDLE')]) t = Table(data) t.setStyle(style) self.story.append(t) def estiloPC(self): return ParagraphStyle(name="centrado", alignment=TA_CENTER) def numeroPagina(self,canvas,doc): num = canvas.getPageNumber() text = "Pagina %s" % num canvas.drawRightString(200*mm, 20*mm, text)
ReportePersona es una clase Python que contiene los métodos agrupados de tal manera de hacer el código mas desacoplado y legible, en el constructor __init__ se crea un buffer que servirá como archivo temporal durante el tiempo que se genera el documento pdf, esto es deseable debido a que nos encontramos en un entorno web donde la eficiencia del código debe ser un requisito fundamental. Ademas el uso del buffer nos permite que el documento se pueda descargar a nuestro sistema de archivos y no se almacene en el servidor, el cual es el comportamiento por defecto de la clase SimpleDocTemplate si se pasa como parámetro una cadena con el nombre del archivo.
El método encabezado agrega un párrafo centrado y a continuación un espaciador de 1.3cm.
El método crearTabla genera una lista de listas por comprensión que se utiliza para llenar la tabla.
Finalmente el método numeroPagina se encarga de agregar una cadena con el número de cada página.

Sin mas que mencionar espero que estos pequeños snippets les sean útiles.
Reportlab Docs
Comentarios
Publicar un comentario