Anuncios

Bienvenidos sean a este post, hoy veremos como tener informacion persistente con python pero en base de datos.

Anuncios
Anuncios

Cuando hablamos de base de datos no solamente nos referimos a las archi conocidas como mysql, SQL, Oracle y «demases» sino tambien a la forma como trabajan muchos lenguajes en el dia de hoy y esto es a traves de ORM, Mapeo Relacional de Objeto por sus siglas en Ingles, siendo basicamente una forma mas estandar para conectarse a las base de datos y trabajar con ellas dado que cada base de datos tiene su forma de trabajar con sus elementos pero en algunas oportunidades no nos bastara y deberemos utilizar los comandos de cada uno de ellas, lo malo de esto es que deberemos tener distintas conexiones para cada tipo de base, igualmente nuestro objetivo es lograr algo mas intermedio entre ORM y las conexiones de bases, para este post veremos como trabajar con sqlalchemy el cual es el ORM mas popular de python, para instalarlo deberemos hacer lo siguiente:

Para instalar en un Debian:
$ sudo apt-get install python3-sqlalchemy
Anuncios
Para instalar en Windows mediante pip:
pip install SQLAlchemy
Anuncios

Una vez instalado podemos pasar a trabajar con un ejemplo para entender como conectarnos a una base, para ello primero crearemos un nuevo archivo al que llamaremos modelos_alquimia.py y le agregaremos el siguiente codigo:

modelos_alquimia.py

from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import ( Column, Integer, String,
	ForeignKey, create_engine)
from sqlalchemy.orm import relationship

engine = create_engine('sqlite:///:memory:')
Base = declarative_base()

class Persona(Base):
	__tablename__ = 'persona'

	id = Column(Integer, primary_key=True)
	nombre = Column(String)
	edad = Column(Integer)

	direcciones = relationship(
		'Direccion',
		back_populates='persona',
		order_by='Direccion.email',
		cascade='all, delete-orphan'
	)

	def __repr__(self):
		return f'{self.nombre}(id={self.id})'

class Direccion(Base):
	__tablename__ = 'direccion'

	id = Column(Integer, primary_key=True)
	email = Column(String)
	id_persona = Column(ForeignKey('persona.id'))
	persona = relationship('Persona', back_populates='direcciones')

	def __str__(self):
		return self.email
	__repr__ = __str__

Base.metadata.create_all(engine)
Anuncios

Este es un codigo muy importante por lo tanto analizaremos distintos bloques:

from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import ( Column, Integer, String,
	ForeignKey, create_engine)
from sqlalchemy.orm import relationship
Anuncios

La primera linea nos permite importar una funcion que nos permite construir una clase base para definiciones de clases declarativas, la siguiente linea nos permite importar no solo el tipo de elemento sino tambien varios tipos y entre ellos uno para la clave y otro para crear un engine, la ultima sera para lograr las relaciones entre las distintas tablas, pasemos al siguiente bloque:

engine = create_engine('sqlite:///:memory:')
Base = declarative_base()
Anuncios

En este caso creamos dos objetos, el primero sera el engine que servira para la conexion y en este caso lo usaremos en memoria (se puede especificar un servidor) y el siguiente objeto sera nuestra «base» para crear las tablas, veamos el primer metodo:

class Persona(Base):
	__tablename__ = 'persona'

	id = Column(Integer, primary_key=True)
	nombre = Column(String)
	edad = Column(Integer)

	direcciones = relationship(
		'Direccion',
		back_populates='persona',
		order_by='Direccion.email',
		cascade='all, delete-orphan'
	)

	def __repr__(self):
		return f'{self.nombre}(id={self.id})'
Anuncios

Esta clase sera para crear a las personas en nuestra base, primero pasaremos el nombre a la tabla (__tablename__), lo siguiente seran las tres columnas de la tabla (id, nombre, edad) luego crearemos un objeto llamado direcciones el cual hara la relacion entre esta tabla y la de Direccion, back_populates establece contra quien compararse y la ultima opcion establece como trabaja la creacion y borrado en el mismo, por ultimo el metodo que definimos __repr__ es el encargado de devolver la representacion del objeto, pasemos a la siguiente clase:

class Direccion(Base):
	__tablename__ = 'direccion'

	id = Column(Integer, primary_key=True)
	email = Column(String)
	id_persona = Column(ForeignKey('persona.id'))
	persona = relationship('Persona', back_populates='direcciones')

	def __str__(self):
		return self.email
	__repr__ = __str__
Anuncios

Esta es muy similar a la anterior pero sera la otra mitad de la relacion, definimos el nombre de la tabla, luego estableceremos las columnas, una para la identificacion, otra para el email y la ultima recibira el valor en base al id de la otra tabla (persona) y por ultimo estableceremos la relacion entre ambas tablas, por ultimo tenemos una declaracion de metodo para __str__ que devolvera el email que contenga y por ultimo se lo asignaremos a __repr__ para que lo devuelva, con esto tenemos las dos clases explicada y las dos tablas que usaremos, por ultimo tenemos la accion que se encarga de crear todo, la base y las dos tablas, con todo esto creado podemos volver al interprete e importaremos los primeros elementos:

>>> from modelos_alquimia import Persona, Direccion, engine
>>> from sqlalchemy.orm import sessionmaker
Anuncios

Primero importaremos las clases que creamos recien y luego la de sessionmaker de sqlalchemy.orm, nuestro siguiente paso sera crear dos objetos:

>>> Sesion = sessionmaker(bind=engine)
>>> sesion = Sesion()
Anuncios

Con estos dos objetos crearemos la sesion que nos conectara al servidor por medio de engine, nuestro siguiente paso sera crear a dos personas:

>>> tinchicus = Persona(nombre='Martin Miranda', edad=44)
>>> mrbogusa = Persona(nombre='Martin H. Miranda', edad=33)
Anuncios

Aqui crearemos dos personas con sus respectivos datos a traves de la clase persona y esto hace que ya esten creadas en la tabla persona, nuestro siguiente paso sera agregar las direcciones de correo:

>>> mrbogusa.direcciones = [
...     Direccion(email='mrbogusa@yahoo.com'),
...     Direccion(email='mrbogusa@gmail.com'),
... ]
>>>
Anuncios

Con esto agregamos las dos direcciones para la persona mrbogusa, vamos a agregar las direcciones para tinchicus:

>>> tinchicus.direcciones.append(Direccion(email='tinchicus@gmail.com'))
>>> tinchicus.direcciones.append(Direccion(email='bogusoft@hotmail.com'))
>>>
Anuncios

Como podemos ver esta es otra alternativa para agregar los correos para la otra persona, donde usaremos append para la relacion que establecimos y luego creamos el objeto correspondiente, por ultimo vamos a hacer lo siguiente:

>>> sesion.add(tinchicus)
>>> sesion.add(mrbogusa)
>>> sesion.commit()
>>>
Anuncios

Con esto realmente agregamos los elementos en la base y tablas correspondientes, y la ultima linea sera la encargada de ejecutar las acciones anteriores, esto equivale a un submit, para nuestro siguiente paso sera verificar si todo se realizo, usemos el siguiente codigo:

>>> tinchicus = sesion.query(Persona).filter(
...     Persona.nombre=='Martin Miranda'
...     ).first()
>>> print(tinchicus, tinchicus.direcciones)
Martin Miranda(id=1) [bogusoft@hotmail.com, tinchicus@gmail.com]
>>>
Anuncios

Crearemos un nuevo objeto llamado tinchicus y este usaremos a sesion para hacer un query a la tabla Persona y por medio de Filter le diremos que busque el campo nombre con el valor correspondiente y first sera para que se detenga en la primer coincidencia, por ultimo mostraremos el valor almacenado en tinchicus y el valor en direcciones gracias a la relacion entre ambas, por ultimo se ven todos los datos solicitados, ahora vamos a hacer lo siguiente:

>>> tinchicus_id = tinchicus.id
>>> del tinchicus
>>>
Anuncios

Con los datos obtenidos anteriormente podemos proceder a crear un nuevo objeto que almacenara el id obtenido con la busqueda anterior y podemos proceder a eliminar el objeto creado originalmente, para nuestro siguiente paso vamos a crear un nueva funcion para mostrar toda la informacion de nuestras tablas:

>>> def mostrar_info():
...     direcciones = sesion.query(Direccion).all()
...     for direccion in direcciones:
...             print(f'{direccion.persona.nombre} <{direccion.email}>')
...     print('personas: {}, direcciones: {}'.format(
...             sesion.query(Persona).count(),
...             sesion.query(Direccion).count())
...     )
... 
>>>
Anuncios

Primero le diremos que busque todas las direcciones contenidas en la clase Direccion, luego por medio de un bucle obtendremos cada una de ellas y mostraremos en pantalla primero el nombre de la persona seguida de las direcciones que posean, por ultimo mostraremos la cantidad de personas y de emails cargados en la base a traves de la funcion count, probemos para ver como funciona:

>>> mostrar_info()
Martin Miranda <tinchicus@gmail.com>
Martin Miranda <bogusoft@hotmail.com>
Martin H. Miranda <mrbogusa@yahoo.com>
Martin H. Miranda <mrbogusa@gmail.com>
personas: 2, direcciones: 4
>>>
Anuncios

Como podemos ver nos trajo toda la informacion de ambas tablas de la base y las cantidades correspondientes, para nuestro siguiente paso vamos a hacer lo siguiente:

>>> tinchicus = sesion.query(Persona).get(tinchicus_id)
>>> sesion.delete(tinchicus)
>>> sesion.commit()
>>>
Anuncios

En este caso recuperaremos en un nuevo objeto al elemento relacionado con el id que guardamos en tinchicus_id, luego procedemos a eliminarlo y por ultimo con el commit ejecutamos la accion, volvamos a mostrar la info de la base para ver como afectaron los cambios:

>>> mostrar_info()
Martin H. Miranda <mrbogusa@yahoo.com>
Martin H. Miranda <mrbogusa@gmail.com>
personas: 1, direcciones: 2
>>>
Anuncios

Por ultimo podemos ver como ahora solo nos quedo una persona y como sigue funcionando correctamente la funcion, con esto completamos una vision basica de como manipular informacion por medio de base de datos.

Anuncios

En resumen, hoy hemos visto como trabajar con ORM para conectarnos a base de datos, hemos visto como utilizar la mas popular de estas, hemos visto como instalar en Debian y Windows por medio de pip, hemos visto como crear la base, las tablas y como relacionarlas entre si, despues hemos visto como cargar informacion, recuperarla y eliminarla, espero les haya sido de utilidad sigueme en tumblr, Twitter o Facebook para recibir una notificacion cada vez que subo un nuevo post en este blog, nos vemos en el proximo post.

Anuncios

Donación

Es para mantenimento del sitio, gracias!

$1.50