Regístrate para acceder a más de 15 cursos gratuitos de programación con un simulador

Trabajo con bases de datos en Flask Python: Desarrollo web con Flask

Ya vamos avanzando! Ahora que sabes cómo construir vistas, manejar formularios y estructurar tu app, es momento de dar el siguiente paso.

🔄 Hasta ahora, los datos se guardaban en memoria (en la sesión), pero es hora de trabajar con una base de datos real, como PostgreSQL. Vamos a hacerlo paso a paso, como un pequeño taller para guardar y consultar información de forma eficiente.

En esta lección vas a:

  1. Instalar las herramientas necesarias.
  2. Configurar tu app para conectarte a PostgreSQL.
  3. Crear la estructura de una tabla para guardar autos. 🚗
  4. Reescribir el repositorio de autos (CarRepository) para trabajar con datos reales.

Paso 1: Instalamos las dependencias

Vamos a utilizar PostgreSQL, una base de datos libre y muy poderosa. Para que Python pueda conversar con ella, necesitamos instalar una biblioteca llamada psycopg. Esta librería es un puente entre Python y PostgreSQL.

Para instalarla, puedes usar pip:

pip install psycopg[binary]

Paso 2: Configuramos la conexión a la base de datos

Ahora conectamos nuestra aplicación a la base de datos con un objeto llamado conn (de “connection”). Este objeto se crea con una línea de código:

import psycopg2

conn = psycopg2.connect(DATABASE_URL)

DATABASE_URL es una variable de entorno que contiene la dirección de tu base de datos. Por ahora basta con saber que puedes definir esa variable según cómo esté configurado tu entorno, por ejemplo en tu .env.

💡 Nota: Más adelante se puede usar una librería como python-dotenv para manejar las variables de entorno.

Paso 3: Creamos la estructura de la base de datos

Como ya dijimos, vamos a trabajar con autos. Vamos a guardar autos con dos campos: manufacturer (marca) y model (modelo). Para eso, creamos una tabla en SQL.

1. Creamos el archivo init.sql

Este archivo define la estructura de la tabla:

CREATE TABLE IF NOT EXISTS cars (
    id SERIAL PRIMARY KEY,
    manufacturer VARCHAR(255) NOT NULL,
    model VARCHAR(255) NOT NULL
);

Este código crea una tabla cars, con tres columnas: un identificador único id, una marca, y un modelo.

2. Creamos un script para ejecutar la creación

Creamos un archivo llamado build.sh:

#!/usr/bin/env bash

psql -a -d $DATABASE_URL -f init.sql

Este script ejecuta el archivo SQL y construye la tabla en la base. Lo hacemos ejecutable con:

chmod +x ./build.sh</code></pre>

Y lo conectamos al <code>Makefile</code> del proyecto así:

<pre><code>build:
    ./build.sh

Con esto, puedes correr make build para crear la estructura de la base.


Paso 4: Creamos el repositorio CarRepository

Toda la lógica para interactuar con la tabla cars vive en esta clase. Vamos a encapsular todo el acceso a la base de datos, para que el resto de la aplicación solo tenga que usar métodos como save() o get_content() sin preocuparse por SQL.

import psycopg2
from psycopg2.extras import DictCursor

class CarRepository:
    def __init__(self, conn):
        self.conn = conn  # Conexión a la base

    def get_content(self):
        # Devuelve todos los autos en forma de lista de diccionarios
        with self.conn.cursor(cursor_factory=DictCursor) as cur:
            cur.execute("SELECT * FROM cars")
            return [dict(row) for row in cur]

    def find(self, id):
        # Busca por id
        with self.conn.cursor(cursor_factory=DictCursor) as cur:
            cur.execute("SELECT * FROM cars WHERE id = %s", (id,))
            row = cur.fetchone()
            return dict(row) if row else None

    def get_by_term(self, search_term=''):
        # Busca por término en marca o modelo
        with self.conn.cursor(cursor_factory=DictCursor) as cur:
            cur.execute("""
                SELECT * FROM cars
                WHERE manufacturer ILIKE %s OR model ILIKE %s
            """, (f'%{search_term}%', f'%{search_term}%'))
            return cur.fetchall()

    def save(self, car):
        if 'id' in car and car['id']:
            self._update(car)
        else:
            self._create(car)

    def _update(self, car):
        with self.conn.cursor() as cur:
            cur.execute(
                "UPDATE cars SET manufacturer = %s, model = %s WHERE id = %s",
                (car['manufacturer'], car['model'], car['id'])
            )
        self.conn.commit()

    def _create(self, car):
        with self.conn.cursor() as cur:
            cur.execute(
                "INSERT INTO cars (manufacturer, model) VALUES (%s, %s) RETURNING id",
                (car['manufacturer'], car['model'])
            )
            id = cur.fetchone()[0]  # Captura el ID del nuevo auto
            car['id'] = id
        self.conn.commit()

¿Qué estamos haciendo?

  • Usamos cursores (cursor()) para ejecutar sentencias SQL
  • Convertimos cada fila a un diccionario para facilitar su lectura
  • Usamos commit() cuando modificamos datos

Paso 5: Usamos el repositorio desde los controladores

La estructura de nuestros controladores no cambia mucho. Solo cambió la “fuente de datos”: antes era la sesión, ahora es la base.

from validator import validate

conn = psycopg2.connect(DATABASE_URL)
repo = CarRepository(conn)

@app.route('/cars')
def cars_index():
    term = request.args.get('term', '')
    if term:
        cars = repo.get_by_term(term)
    else:
        cars = repo.get_content()
    return render_template('cars/index.html', search=term, cars=cars)

@app.route('/cars/<int:id>')
def cars_show(id):
    car = repo.find(id)
    if car is None:
        abort(404)
    return render_template('cars/show.html', car=car)

@app.route('/cars/new')
def cars_new():
    return render_template('cars/new.html', car={}, errors={})

@app.route('/cars', methods=['POST'])
def cars_post():
    data = request.form.to_dict()
    errors = validate(data)

    if not errors:
        car = {'manufacturer': data['manufacturer'], 'model': data['model']}
        repo.save(car)
        flash('El auto fue agregado exitosamente', 'success')
        return redirect(url_for('cars_index'))

    return render_template('cars/new.html', car=data, errors=errors), 422

Fíjate que gracias a que separamos las responsabilidades, no tuvimos que cambiar nada en las vistas o formularios. Solo cambiamos la fuente de datos y mantuvimos las interfaces del repositorio.


Resumen

  • Antes usábamos la sesión para guardar datos; ahora usamos una base PostgreSQL
  • Instalamos psycopg para conectar Python con PostgreSQL
  • Creamos un archivo init.sql para definir la tabla cars
  • Creamos el script build.sh para ejecutar esa estructura fácilmente
  • Organizamos el código de acceso a la base en la clase CarRepository
  • Los métodos de esta clase encapsulan las operaciones SQL (crear, actualizar, buscar, listar)
  • La interfaz del repositorio nos permitió no modificar los controladores

Ahora puedes construir aplicaciones que trabajan con datos reales y las puedes preparar para producción o desarrollo colaborativo.


Trabajo independiente

  1. Cambia la forma de almacenamiento de usuarios para que se guarden en una base de datos.
  2. Verifícalo: al pasar del almacenamiento en sesión al almacenamiento en base de datos, el código de la aplicación no debería cambiar. Lo único que debe modificarse es el código de la abstracción Repositorio.
  3. Elimina los controladores y plantillas innecesarios. Deja solo todo lo relacionado con users.

Repositorio de referencia


Materiales adicionales

  1. Conexión a Postgres
  2. Psycopg

Para acceder completo a curso necesitas un plan básico

El plan básico te dará acceso completo a todos los cursos, ejercicios y lecciones de Códica, proyectos y acceso de por vida a la teoría de las lecciones completadas. La suscripción se puede cancelar en cualquier momento.

Obtener acceso
130
cursos
1000
ejercicios
2000+
horas de teoría
3200
test

Obtén acceso

Cursos de programación para principiantes y desarrolladores experimentados. Comienza tu aprendizaje de forma gratuita

  • 130 cursos, 2000+ horas de teoría
  • 1000 ejercicios prácticos en el navegador
  • 360 000 estudiantes
Al enviar el formulario, aceptas el «Política de privacidad» y los términos de la «Oferta», y también aceptas los «Términos y condiciones de uso»

Nuestros graduados trabajan en empresas como:

Bookmate
Health Samurai
Dualboot
ABBYY