Actualizado 5 junio 2026 · 12 min de lectura
Generar reportes Excel desde base de datos con Python (API + JSON)
Cada mes, miles de desarrolladores escriben scripts para extraer datos de PostgreSQL, MySQL o SQLite y convertirlos en reportes Excel. El proceso siempre es el mismo: query SQL, iterar filas, formatear celdas con openpyxl, ajustar anchos de columna, aplicar estilos... y al final tienes 200 líneas de código para un archivo .xlsx.
Hay una forma más simple: consulta tu base de datos, envía los resultados como JSON a una API, recibe el Excel formateado. Sin openpyxl. Sin xlsxwriter. Sin dependencias de renderizado.
Por qué generar Excel con una API en lugar de openpyxl
| Criterio | openpyxl / xlsxwriter | API REST (Reportia) |
|---|---|---|
| Líneas de código | 150-300 por reporte | 15-20 por reporte |
| Formato condicional | Manual, verbose | Declarativo en JSON |
| Múltiples hojas | Código repetitivo | Array de sheets en JSON |
| Plantillas reutilizables | No (código hardcoded) | Sí (template + data) |
| Dependencias | openpyxl + lxml | Solo requests |
| Mantenimiento | Cambio de formato = cambio de código | Cambio de formato = cambio de JSON |
Paso 1: Consulta tu base de datos
Empieza con tu query habitual. Aquí usamos SQLite como ejemplo, pero funciona igual con PostgreSQL (psycopg2) o MySQL (pymysql):
import sqlite3
conn = sqlite3.connect("ventas.db")
conn.row_factory = sqlite3.Row # resultados como dict
cursor = conn.execute("""
SELECT
producto,
cantidad,
precio_unitario,
cantidad * precio_unitario AS total,
fecha_venta
FROM ventas
WHERE fecha_venta >= '2026-01-01'
ORDER BY fecha_venta DESC
""")
filas = [dict(row) for row in cursor.fetchall()]
print(f"{len(filas)} ventas encontradas")
Con PostgreSQL, el código es casi idéntico:
import psycopg2
from psycopg2.extras import RealDictCursor
conn = psycopg2.connect("postgresql://user:pass@localhost/ventas_db")
cursor = conn.cursor(cursor_factory=RealDictCursor)
cursor.execute("SELECT producto, cantidad, precio_unitario, ...")
filas = cursor.fetchall()
Paso 2: Envía los datos a la API como JSON
Una vez que tienes tus datos como lista de diccionarios, envíalos a la API:
import requests
response = requests.post(
"https://reportia.4l3.org/v1/render",
json={
"template": "reporte-ventas",
"format": "xlsx",
"data": {
"titulo": "Reporte de Ventas Q1 2026",
"empresa": "Mi Empresa SA de CV",
"fecha_generacion": "2026-06-05",
"filas": filas,
"resumen": {
"total_ventas": sum(f["total"] for f in filas),
"productos_unicos": len(set(f["producto"] for f in filas)),
"promedio_por_venta": sum(f["total"] for f in filas) / len(filas)
}
}
},
headers={"Authorization": "Bearer TU_API_KEY"}
)
# Guardar el Excel
with open("reporte_ventas_q1.xlsx", "wb") as f:
f.write(response.content)
print("Reporte generado: reporte_ventas_q1.xlsx")
Eso es todo. 15 líneas para generar un Excel profesional con encabezados formateados, anchos de columna automáticos y fila de totales.
Paso 3: Reportes con múltiples hojas
Para reportes más complejos con varias hojas (ventas por mes, por producto, resumen ejecutivo):
from collections import defaultdict
# Agrupar por mes
ventas_por_mes = defaultdict(list)
for fila in filas:
mes = fila["fecha_venta"][:7] # "2026-01"
ventas_por_mes[mes].append(fila)
# Generar Excel multi-hoja
response = requests.post(
"https://reportia.4l3.org/v1/render",
json={
"template": "reporte-mensual",
"format": "xlsx",
"data": {
"sheets": [
{
"nombre": f"Ventas {mes}",
"filas": ventas,
"total": sum(v["total"] for v in ventas)
}
for mes, ventas in sorted(ventas_por_mes.items())
],
"resumen": {
"titulo": "Reporte Trimestral",
"meses": len(ventas_por_mes),
"gran_total": sum(f["total"] for f in filas)
}
}
},
headers={"Authorization": "Bearer TU_API_KEY"}
)
Automatizar con cron (reporte semanal/mensual)
Combina el script con un cron job para reportes automáticos:
# Crontab: cada lunes a las 7am
0 7 * * 1 /usr/bin/python3 /opt/scripts/reporte_semanal.py
Y si necesitas enviar el reporte por email automáticamente:
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.base import MIMEBase
from email import encoders
msg = MIMEMultipart()
msg["Subject"] = "Reporte Ventas Semanal"
msg["From"] = "[email protected]"
msg["To"] = "[email protected]"
adjunto = MIMEBase("application", "octet-stream")
adjunto.set_payload(response.content)
encoders.encode_base64(adjunto)
adjunto.add_header("Content-Disposition", "attachment", filename="reporte.xlsx")
msg.attach(adjunto)
with smtplib.SMTP("smtp.gmail.com", 587) as server:
server.starttls()
server.login("[email protected]", "app_password")
server.send_message(msg)
Ejemplo con JavaScript (Node.js)
const response = await fetch("https://reportia.4l3.org/v1/render", {
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": "Bearer TU_API_KEY"
},
body: JSON.stringify({
template: "reporte-ventas",
format: "xlsx",
data: {
titulo: "Reporte Ventas",
filas: rows // array de objetos
}
})
});
const buffer = await response.arrayBuffer();
fs.writeFileSync("reporte.xlsx", Buffer.from(buffer));
Ejemplo con cURL
curl -X POST https://reportia.4l3.org/v1/render \
-H "Content-Type: application/json" \
-H "Authorization: Bearer TU_API_KEY" \
-d '{
"template": "reporte-ventas",
"format": "xlsx",
"data": {
"titulo": "Reporte Ventas",
"filas": [
{"producto": "Widget A", "cantidad": 50, "total": 500},
{"producto": "Widget B", "cantidad": 30, "total": 450}
]
}
}' -o reporte.xlsx
Genera tu primer reporte Excel gratis
50 documentos/mes en el plan gratuito. Sin tarjeta de crédito.
Empezar gratis →Preguntas frecuentes
¿Puedo generar Excel con formato condicional desde una API?
Sí. Reportia aplica formato condicional basado en reglas que defines en el JSON: colores por rango de valores, negritas en totales, bordes en encabezados. Todo sin tocar openpyxl.
¿Qué diferencia hay entre generar Excel con openpyxl vs una API?
openpyxl requiere instalar la librería, manejar celdas individualmente y formatear manualmente. Con una API, envías JSON con tus datos y recibes el Excel formateado. Menos código, menos dependencias, misma calidad.
¿Puedo generar reportes Excel con múltiples hojas?
Sí. Envía un array de sheets en el JSON, cada uno con su nombre, datos y formato. La API genera un único archivo .xlsx con todas las hojas.
¿Funciona con bases de datos grandes (100k+ filas)?
Sí. La API acepta hasta 500MB de payload. Para datasets muy grandes, considera paginar o pre-agregar los datos antes de enviarlos.