ORM (Object-relational mapping) un poquito de sqlalchemy

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:
- Es más potente que SQLObject
- 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 "<User('%s','%s')>" % (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 "<Address('%s')>" % 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.




Me ha venido que ni pintada esta introducción para poder usar una pequeña base de datos para mi proyecto, gracias dani ;)
Saludos!!
- reply
Submitted by Virako (not verified) on Thu, 05/03/2009 - 23:17.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.
...
- reply
Submitted by danigm on Thu, 11/12/2008 - 10:02.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.
- reply
Submitted by J. Félix Ontañón (not verified) on Thu, 11/12/2008 - 00:04.