ORM (Object-relational mapping) un poquito de sqlalchemy

GECO's picture

En el esquema de la arquitectura de GECO aparece como una parte bastante importante en el demonio "gecod" SQLObject.

Un ORM simplifica el acceso a una base de datos por parte del programador convirtiendo toda sentencia sql a operaciones con objetos. Así por ejemplo añadir una fila a una tabla es tan fácil como crear un objeto.

Después de algún tiempo pensandolo he decidido que sería mejor opción utilizar SQLAlchemy, ¿por qué este cambio? Bueno, son varias razones las que me han llevado finalmente a explorar este nuevo ORM:

  1. Es más potente que SQLObject
  2. Ya conocía SQLObject, una oportunidad de conocer otro ORM

He estado mirando un poco la documentación de SQLAlchemy y voy a explicar de forma breve la manera más sencilla de utilizar este ORM en python.

Definición de una tabla/objeto

from sqlalchemy import *
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import relation, backref, sessionmaker

Base = declarative_base()
metadata = Base.metadata

class User(Base):
__tablename__ = 'users'

id = Column(Integer, primary_key=True)
name = Column(String(20))
fullname = Column(String(50))

def __init__(self, name, fullname):
self.name = name
self.fullname = fullname

def __repr__(self):
return "" % (self.name, self.fullname)

db = create_engine('sqlite:///database.sqlite', echo=False)
metadata.create_all(db)

Así de fácil se declara un simple objeto. Esto se refleja en una base de datos con una tabla, de nombre 'users', con las columnas id, name y fullname.

Con metadata.create_all(db) se crea la tabla en la base de datos (La base de datos puede ser sqlite, mysql, postgresql,...).

Creación de objetos

Session = sessionmaker(bind=db, autoflush=True)
session = Session()
u = User('dani', 'daniel garcia')
session.save(u)
session.commit()

De esta forma tan simple se pueden crear usuarios que se verán reflejados en la base de datos relacional como una nueva fila en la tabla de usuarios.

Es necesario crear un objeto de tipo session para interactuar con la base de datos.

Y para eliminar una entrada nada más simple que

session.delete(u)
session.commit()

Consultas

session.query(User).filter(User.name == 'dani').all()

Se pueden hacer multitud de consultas con filter y además se pueden concatenar filters -> filter(User.name == 'dani').filter(User.fullname == 'daniel garcia')....

Relaciones

class Address(Base):
__tablename__ = 'addresses'

id = Column(Integer, primary_key=True)
email_address = Column(String, nullable=False)
user_id = Column(Integer, ForeignKey('users.id'))

user = relation(User, backref=backref('addresses',
order_by=id, cascade='all, delete-orphan',
passive_deletes=False))

def __init__(self, email_address):
self.email_address = email_address

def __repr__(self):
return "

" % self.email_address

Si queremos declarar una tabla que esté relacionada con otra se utiliza ForeignKey. Además hay que definir una relación, y backref nos da la referencia en la tabla padre, es decir que la tabla padre tendrá este atributo. Con cascade y passive_deletes se consigue el borrado en cascada, cuando se borre un usuario se borraran todas los emails asociados a este.

u = session.query(User).filter_by(name='dani').one()
print u.addresses
u.addresses.append(Address('dani@danigm.net'))
print u.addresses
session.commit()
session.query(User, Address).filter(User.id == Address.user_id).filter(Address.email_address == 'dani@danigm.net').first()

Con este ejemplo se ve como se pueden hacer consultas sobre la unión de varias tablas.

Comments

3
J. Félix Ontañón's picture

Interesante, ya me comentaste algo sobre SQLAlchemy y salvo por las consultas encadenadas filter().filter().filter(), curioso aunque implementable con SQL a pelo, no veo en tus ejemplos ninguna power-feature que no pueda encontrar en SQLObject.

Supongo, claro, que es porque se trata de una introducción muy básica, pero sería interesante que destacaras algunas características originales de SQLAlchemy.

danigm's picture

Algunas ventajas frente a SQLObject:

- Soporta bases de datos oracle.
- Tiene soporte de claves compuestas, la clave primaria puede ser más de un campo.
- Una tabla se puede referenciar a si misma.
- Se puede adaptar a cualquier base de datos ya creada.
- Las consultas son más eficientes.
...

Virako's picture

Me ha venido que ni pintada esta introducción para poder usar una pequeña base de datos para mi proyecto, gracias dani ;)

Saludos!!