Reportia

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

Criterioopenpyxl / xlsxwriterAPI REST (Reportia)
Líneas de código150-300 por reporte15-20 por reporte
Formato condicionalManual, verboseDeclarativo en JSON
Múltiples hojasCódigo repetitivoArray de sheets en JSON
Plantillas reutilizablesNo (código hardcoded)Sí (template + data)
Dependenciasopenpyxl + lxmlSolo requests
MantenimientoCambio de formato = cambio de códigoCambio 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.