Construir

Conectar Flask a PostgreSQL: guía práctica

Cómo conectar una app Flask a PostgreSQL con psycopg2: la cadena de conexión, consultas seguras, y el manejo de conexiones que evita que tu app se caiga bajo carga.

SQLite es perfecto para empezar, pero cuando tu app crece o necesitas que varios procesos accedan a la vez, toca dar el salto a PostgreSQL. Aquí conectamos Flask a Postgres de forma directa y segura, entendiendo cada pieza en vez de esconderlo todo tras un ORM.

Instalar el conector

pip install psycopg2-binary

Un apunte: la versión psycopg2-binary trae todo listo para desarrollo y es la que quieres para empezar. Existe también psycopg2 a secas, que requiere compilar y dependencias del sistema; esa se reserva para ciertos entornos de producción. Para arrancar, la -binary es la correcta.

La conexión

import psycopg2
from psycopg2.extras import RealDictCursor

def get_db():
    return psycopg2.connect(
        host="localhost",
        dbname="mi_base",
        user="postgres",
        password="tu_password",
        cursor_factory=RealDictCursor,
    )

El RealDictCursor es un detalle que agradecerás: hace que las consultas devuelvan diccionarios (fila["nombre"]) en lugar de tuplas (fila[0]). Trabajar con nombres de columna en vez de posiciones numéricas hace el código mucho más legible y menos propenso a errores cuando cambias el orden de las columnas.

Consultar datos

from flask import Flask, jsonify

app = Flask(__name__)

@app.route("/usuarios")
def listar_usuarios():
    conn = get_db()
    cur = conn.cursor()
    cur.execute("SELECT id, nombre, email FROM usuarios")
    usuarios = cur.fetchall()
    cur.close()
    conn.close()
    return jsonify(usuarios)

Fíjate en el cur.close() y conn.close() al final. Cada conexión que abres debes cerrarla. Si las dejas abiertas, se van acumulando hasta que PostgreSQL rechaza nuevas conexiones y tu app se cae con un error de “too many connections”. Es el problema silencioso más común al usar Postgres sin ORM.

Insertar datos de forma segura

Aquí está la regla de oro de seguridad, la misma que con SQLite pero conviene repetir porque es crítica:

@app.route("/usuarios", methods=["POST"])
def crear_usuario():
    datos = request.get_json()
    conn = get_db()
    cur = conn.cursor()
    cur.execute(
        "INSERT INTO usuarios (nombre, email) VALUES (%s, %s) RETURNING id",
        (datos["nombre"], datos["email"]),
    )
    nuevo_id = cur.fetchone()["id"]
    conn.commit()
    cur.close()
    conn.close()
    return jsonify({"id": nuevo_id}), 201

Nunca metas los datos directamente en la consulta con f-strings o concatenación. Usa los marcadores %s y pasa los valores aparte, como en el ejemplo. Eso previene la inyección SQL, el agujero de seguridad más clásico. Psycopg2 se encarga de escapar los valores correctamente.

Dos cosas más: el conn.commit() es obligatorio para que el INSERT se guarde de verdad (sin él, los cambios se pierden al cerrar), y el RETURNING id es una función útil de PostgreSQL que te devuelve el id del registro recién creado en la misma consulta.

El patrón que evita que la app se caiga

Cerrar conexiones a mano en cada ruta es frágil: si una consulta lanza un error antes del close, la conexión queda colgada. La forma robusta es usar try/finally:

@app.route("/usuarios")
def listar_usuarios():
    conn = get_db()
    try:
        cur = conn.cursor()
        cur.execute("SELECT id, nombre FROM usuarios")
        return jsonify(cur.fetchall())
    finally:
        conn.close()

El bloque finally se ejecuta pase lo que pase —haya error o no—, así que la conexión siempre se cierra. Este patrón es lo que separa una app que aguanta uso real de una que se degrada con el tiempo hasta caerse.

Con esto tienes Flask hablando con PostgreSQL de forma segura y estable. A partir de aquí, cuando el proyecto crezca, evaluarás un pool de conexiones o un ORM como SQLAlchemy, pero entender esta base directa te hará usar esas herramientas con criterio en vez de a ciegas.


¿Vas a migrar de SQLite a PostgreSQL o a montar un pool de conexiones? Escríbeme desde contacto y lo cubrimos.

← Más de Construir