HOWTO · Flask

Eliminar un registro en Flask SQLAlchemy

Aprende a eliminar un registro en Flask-SQLAlchemy: carga una instancia del modelo por su clave primaria con db.session.get(), márcala con db.session.delete() y haz que la eliminación sea persistente con db.session.commit().

En esta página

Eliminar un registro en Flask-SQLAlchemy consta de tres pasos: cargar la instancia del modelo, pasarla a db.session.delete() y confirmar la transacción con db.session.commit(). El patrón básico es este:

El código y las etiquetas o salidas visibles de esta sección se mantienen en inglés.

def delete_customer(customer_id):
    customer = db.session.get(Customer, customer_id)
    if customer is not None:
        db.session.delete(customer)
        db.session.commit()

db.session.get() obtiene una fila por su clave primaria y devuelve None cuando ninguna fila coincide, db.session.delete() marca la instancia cargada para su eliminación dentro de la sesión y db.session.commit() emite la sentencia DELETE real. Hasta que el commit se realice correctamente, la fila permanece en la base de datos.

Los listados siguientes encapsulan sus llamadas a Flask-SQLAlchemy dentro de funciones para que cada bloque de código sea autocontenido; en tu propio proyecto, las mismas instrucciones se ejecutan a nivel de módulo o dentro de una vista, con db y Customer importados o definidos antes en el archivo.

Instalar Flask-SQLAlchemy y configurar la aplicación

Instala el paquete con pip install flask-sqlalchemy (consulta la página de Flask-SQLAlchemy en PyPI para más detalles). A continuación, indica a la aplicación Flask qué base de datos usar estableciendo SQLALCHEMY_DATABASE_URI antes de crear el objeto SQLAlchemy. Una fábrica de aplicaciones mantiene la configuración en un solo lugar; en un módulo simple, colocarías las dos importaciones al principio del archivo:

El código y las etiquetas o salidas visibles de esta sección se mantienen en inglés.

def create_app():
    from flask import Flask
    from flask_sqlalchemy import SQLAlchemy

    app = Flask(__name__)
    app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///:memory:"
    db = SQLAlchemy(app)
    return app, db

El ajuste acepta cualquier URL de base de datos de SQLAlchemy. La URL de SQLite en memoria que se muestra aquí mantiene los ejemplos autocontenidos; sustitúyela por la URL de tu propia base de datos en una aplicación real.

Definir un modelo y crear un registro

Una eliminación necesita una fila sobre la que trabajar, así que comienza con un pequeño modelo Customer. Cada atributo definido con db.Column se convierte en una columna de la tabla customer. En un proyecto real, la clase se ubica a nivel de módulo en tu archivo de modelos; aquí una función fábrica mantiene el listado autocontenido:

El código y las etiquetas o salidas visibles de esta sección se mantienen en inglés.

def define_models(db):
    class Customer(db.Model):
        id = db.Column(db.Integer, primary_key=True)
        name = db.Column(db.String(50), nullable=False)
        address = db.Column(db.String(200))
        email = db.Column(db.String(50))

    return Customer


def seed_first_customer(app, db):
    Customer = define_models(db)
    with app.app_context():
        db.create_all()
        db.session.add(
            Customer(
                name="Ada Lovelace",
                address="12 Analytical Engine Way",
                email="ada@example.com",
            )
        )
        db.session.commit()

db.create_all() crea la tabla dentro de un contexto de aplicación de Flask, y db.session.add() junto con db.session.commit() inserta el registro. Como id es la clave primaria, la base de datos lo asigna automáticamente al insertar la fila, lo que proporciona un valor estable para buscar el registro más adelante.

Cargar y eliminar un registro

db.session.get(Customer, customer_id) devuelve la instancia correspondiente a esa clave primaria, o None cuando la fila no existe. Comprueba primero si el registro no existe para que el código no pase None a db.session.delete():

El código y las etiquetas o salidas visibles de esta sección se mantienen en inglés.

def delete_customer(customer_id):
    customer = db.session.get(Customer, customer_id)
    if customer is None:
        return "No customer with that id."
    db.session.delete(customer)
    db.session.commit()
    return "Customer deleted."

Llamar a db.session.delete() no elimina la fila inmediatamente. Marca la instancia como pendiente de eliminación dentro de la sesión, y el cambio queda pendiente hasta el siguiente db.session.commit().

Confirmar la eliminación y gestionar los fallos

db.session.commit() envía todos los cambios pendientes, incluida la sentencia DELETE programada, dentro de una sola transacción y los hace duraderos. Omitir el commit significa que la eliminación nunca llega a la base de datos: hasta que se ejecute db.session.commit(), el cambio permanece pendiente dentro de la transacción. Ejecuta este ejemplo para ver cómo una eliminación se vuelve duradera en Python puro:

El código y las etiquetas o salidas visibles de esta sección se mantienen en inglés.

import sqlite3

conn = sqlite3.connect(":memory:")
conn.execute("CREATE TABLE customer (id INTEGER PRIMARY KEY, name TEXT)")
conn.execute("INSERT INTO customer VALUES (1, 'Ada')")

cursor = conn.cursor()
cursor.execute("DELETE FROM customer WHERE id = 1")
conn.commit()

print(cursor.execute("SELECT COUNT(*) FROM customer").fetchone()[0])
0

Un commit también puede fallar, por ejemplo, cuando se infringe una restricción o se interrumpe la conexión. Cuando eso ocurre, la transacción permanece abierta y la sesión no puede ejecutar más consultas hasta que llames a db.session.rollback() para descartar la transacción fallida:

def commit_changes():
    try:
        db.session.commit()
    except Exception:
        db.session.rollback()
        raise

Dado que Flask-SQLAlchemy delimita db.session al contexto de la aplicación, revierte siempre la sesión fallida (o retírala) antes de que se ejecute la siguiente consulta.

Ejemplo completo y verificación del resultado

Al juntar las piezas, este listado configura la aplicación, define el modelo Customer, inserta un registro, lo elimina y vuelve a buscarlo. Requiere que Flask-SQLAlchemy esté instalado; llama a main() en un proyecto que tenga el paquete para ejecutarlo:

El código y las etiquetas o salidas visibles de esta sección se mantienen en inglés.

def main():
    from flask import Flask
    from flask_sqlalchemy import SQLAlchemy

    app = Flask(__name__)
    app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///:memory:"
    db = SQLAlchemy(app)

    class Customer(db.Model):
        id = db.Column(db.Integer, primary_key=True)
        name = db.Column(db.String(50), nullable=False)
        address = db.Column(db.String(200))
        email = db.Column(db.String(50))

    def insert_customer(name, address, email):
        customer = Customer(name=name, address=address, email=email)
        db.session.add(customer)
        db.session.commit()
        return customer.id

    def delete_customer(customer_id):
        customer = db.session.get(Customer, customer_id)
        if customer is None:
            return "No customer with that id."
        db.session.delete(customer)
        db.session.commit()
        return "Customer deleted."

    with app.app_context():
        db.create_all()
        new_id = insert_customer(
            "Ada Lovelace", "12 Analytical Engine Way", "ada@example.com"
        )
        print(delete_customer(new_id))
        print(db.session.get(Customer, new_id))

Cuando se ejecuta main(), el script imprime la cadena en inglés Customer deleted. seguida de None, porque la llamada posterior a db.session.get() no encuentra ninguna fila para la clave primaria eliminada. Para verificar una eliminación en tu propia aplicación, busca el registro de nuevo de la misma manera o ejecuta una consulta filtrada de recuento: un resultado None (o un recuento de cero) confirma que la fila ya no existe.