Consultas con Flask-SQLAlchemy

Publicado por Andrea Navarro en

En este artículo veremos como realizar consultas a base de datos utilizando el ORM Flask-SQLAlchemy. Veremos como insertar, actualizar y eliminar registros.

Flask-SQLAlchemy permite manipular la base de datos a través de los objetos que los representan configurados como modelos en nuestra aplicación. Podremos insertar, actualizar y eliminar registros a partir de objetos de sus clases. De manera similar, es posible realizar consultas a la base de datos y los resultados serán manejados como objetos y listas de objetos.

Insertar elementos

Para insertar un elemento en la base de datos desde nuestra aplicación debemos crear un objeto de la clase correspondiente a la tabla en cuestión verificando que todos los atributos obligatorios tengan un valor y respetando los tipos de valores de las columnas.

class Persona(db.Model):
    personaId = db.Column(db.Integer, primary_key=True)
    nombre = db.Column(db.String(80), nullable=False)
    apellido = db.Column(db.String(80), nullable=False)

    # Constructor
    def __init__(self, nombre, apellido):
        self.nombre = nombre
        self.apellido = apellido

En el siguiente caso deberemos asegurarnos de cargar los atributos nombre y apellido con valores String pero no cargaremos el valor personaId ya que es un valor auto-incremental que será cargado por la base de datos.

Una vez creado solicitamos a Flask-SQLAlchemy que agregue dicho objeto. Para que esté cambio impacte sobre la base de datos es necesario llamar a la función commit. De lo contrario todos los cambios realizados se descartaran al finalizar la solicitud.

persona = Persona('Pedro', 'Moreno') # Crear objeto
db.session.add(persona) # Agregar objeto a la solicitud
db.session.commit() # Hacer commit a la solicitud

Una vez que este objeto esté creado todos aquellos datos que han sido creados por la base de datos (valor de clave primaria auto-incremental, valores por defecto, etc) estarán cargados en nuestro objeto y podremos acceder a ellos.

print(persona.nombre) # Pedro
print(persona.personaId) # 23

Actualizar elemento

El proceso de actualizar un elemento es idéntico que el de insertar. La única diferencia es que el objeto en cuestión debe tener cargado su valor de identificación, de esta manera SQLAlchemy diferencia un elemento nuevo que debe ser insertado de uno al cuál se le debe modificar algunos valores.

Siguiendo el ejemplo anterior es posible modificar alguno o todos los atributos del objeto persona siempre y cuando se mantenga el valor de personaId. Luego debemos guardar estos cambios y realizar un commit.

persona.nombre = 'Marta' # Modificar objeto
db.session.add(persona) # Agregar objeto a la solicitud
db.session.commit() # Hacer commit a la solicitud

Una ver realizado este proceso será posible acceder a los nuevos valores desde nuestro objeto.

print(persona.nombre) # Marta
print(persona.personaId) # 23

Eliminar elementos

Para eliminar un elemento este debe se pasado a la función delete. Al igual que en la función add es necesario realizar un commit para que la solicitud impacte en la base de datos.

db.session.delete(persona) # Solicitar eliminar objeto
db.session.commit() # Hacer commit a la solicitud

Seleccionar elementos

Para seleccionar elementos utilizando SQLAlchemy es necesario utilizar la función execute. Esta función da por resultado un objeto Result que contiene diferentes métodos de trabajar con los valores resultantes de la consulta.

Suponiendo los siguientes modelos representados en una base de datos.

class Persona(db.Model):
    personaId = db.Column(db.Integer, primary_key=True)
    nombre = db.Column(db.String(80), nullable=False)
    apellido = db.Column(db.String(80), nullable=False)
    edad = db.Column(db.Integer)
    ventas = db.relationship("Venta", back_populates="persona",cascade="all,
delete-orphan")

class Venta(db.Model):
    ventaId = db.Column(db.Integer, primary_key=True)
    personaId = db.Column(db.Integer, db.ForeignKey('persona.personaId'),
nullable=False)
    producto = db.Column(db.String(80), nullable=False)
    persona = db.relationship('Persona', back_populates="ventas", uselist=False, single_parent=True)

Para el siguiente caso, si queremos obtener una lista de personas podemos realizarlo a través de la función select.

query = db.select(Persona)
result = db.session.execute(query)
personas = result.scalars()

En la primera linea se arma la consulta correspondiente para la base de datos, en la siguiente se ejecuta y se guarda el resultado como un objeto Result y finalmente la función scalars lo convierte en una lista de objetos Persona. Es posible combinar toda la consulta en una sola linea.

personas = db.session.execute(db.select(Persona)).scalars()

Para obtener un solo elemento es posible utilizar la función one en lugar de scalars.

persona = db.session.execute(db.select(Persona)).one()

Existen otros métodos para manejar los resultados obtenidos por la ejecución de consultas a la base de datos. Puede encontrarse una lista completa en la documentación oficial de SQLAlchemy.

Filtrado

Para filtrar las consultas se utiliza la función where. El siguiente ejemplo da por resultado una lista de las personas en la base de datos con una edad de 30 años.

personas = db.session.execute(db.select(Persona).<strong>where</strong>(edad == 30)).scalars()

Operadores

SQLAlchemy soporta todos los de los operadores de comparación de Python

db.select(Persona).where(edad <strong>==</strong> 30)
db.select(Persona).where(edad <strong>!=</strong> 30)
db.select(Persona).where(edad <strong>>=</strong> 30)
db.select(Persona).where(edad <strong><=</strong> 30)
db.select(Persona).where(edad <strong>></strong> 30)
db.select(Persona).where(edad <strong><</strong> 30)

Para realizar filtrado con columnas que contienen cadenas de caracteres puede utilizarse la función like.

db.select(Persona).where(nombre.like('María'))

Dependiendo de la base de datos utilizada la función like puede traducirse en un formato case-sensitive o no case-sensitive. En el caso de querer asegurar la comparación no case-sensitive debe utilizarse en cambio la función ilike.

db.select(Persona).where(nombre.ilike('María'))

Al igual que en SQL permite colocar símbolos comodines en la comparación.

db.select(Persona).where(nombre.ilike('%ar%'))

Para comparar los valores de la columna con los valores de una lista es posible utilizar las funciones in_ y not_in .

lista = ["María", "Carla", "Gonzalo"]

db.select(Persona).where(nombre.in_(lista))
db.select(Persona).where(nombre.not_in(lista))

Existen diferentes maneras de especificar un operador AND para combinar más de una condición. La más sencilla es separar las condiciones por comas.

db.select(Persona).where(edad == 30 , nombre.ilike('%María%'))

También es posible especificar el operador utilizando la función and_

db.select(Persona).where(and_(edad == 30, nombre.ilike('%María%')))

Finalmente se pueden concatenar varias condiciones where.

db.select(Persona).where(edad == 30).where(nombre.ilike('%María%'))

Para especificar un operador OR se utiliza la función or_

db.select(Persona).where(or_(edad == 30, nombre.ilike('%María%')))

Ordenamiento

Para especificar el ordenamiento requerido para una consulta utilizamos la función order_by a la que se le pasa como parámetro la columna correspondiente.

db.select(Persona).order_by(nombre)

Por defecto el ordenamiento se hace de manera ascendente, si queremos que se haga de manera descendente debemos agregar la función desc.

db.select(Persona).order_by(nombre).desc()

En este artículo hemos visto cómo insertar, actualizar y eliminar registros en una base de datos utilizando Flask-SQLAlchemy. También hemos ejemplificado algunos de los métodos para realizar consultas, filtrar registros y configurar ordenamiento.


¿Preguntas? ¿Comentarios?

Si tenés dudas, o querés dejarnos tus comentarios y consultas, sumate al grupo de Telegram de la comunidad JuncoTIC!
¡Te esperamos!


Andrea Navarro

- Ingeniera en Informática - Docente universitaria - Investigadora