change the way you think about databases and SQL!”. • El lenguaje SQL es: popular, controversial y... considerablemente rechazado por sus propios usuarios. • Las bases de datos relacionales son una gran herramienta. • SQLAlchemy es un tookit.
Object Relational Mapper that gives application developers the full power and flexibility of SQL.” • Liberado en febrero del 2005 • Autor Mike Bayer (aka zzzeek) • Maduro, eficiente, modular, no-opinionado. Acerca del proyecto
datos y adapters en una interfaz tan consistente como sea posible... Filosofía • ...pero exponer los diferentes comportamientos y características de cada backend. • Proveer automatización y DRY. • Permitir expresar las tareas a realizar utilizando patrones declarativos.
• Es una API spec definida para mejorar la consistencia, portabilidad y alcance entre los paquetes python usados para acceder a bases de datos, comúnmente llamados database drivers o adapters. • Muchas implementaciones, ej: • PostgreSQL: psycopg2, pyPgSQL, PyGreSQL, ... • MySQL: mysql-python, pyMySQL, myconnpy, ... • ... 9
cur = conn.cursor() cur.execute("CREATE TABLE registry (key varchar, value varchar)") cur.executemany("INSERT INTO registry (key, value) VALUES (%s, %s)", [("key1", "value1"), ("key2", "value2")]) cur.execute('SELECT key, value FROM registry') for key, value in cur.fetchall(): print key, value conn.commit() cur.close() conn.close()
es una tarea engorrosa. • Si es necesario hablar con mas de una base, es necesario usar mas de un adapter y queda de nuestro lado reusar el código en común y manejar sus diferencias. • Los bound parameters de queries tienen pitfalls. • Debuggear y mantener código se hace muy difícil a medida que la interacción entre la aplicación y la base crece.
a un adapter. • Usa una Connection Pool para reusar conexiones existentes del adapter a la base de datos. • Usa un Dialect que se encarga de hacer la traducción entre la engine y los diferentes adapters.
estructuras de la base de datos, expresiones SQL y tipos de datos usando objetos y demás estructuras de python. • Modelado para parecerse tanto como sea posible al lenguaje de la base de datos en uso. • Abstracción mínima para unificar las diferencias y proveer una API consistente. • No implementa solamente el mínimo común denominador, las features específicas del backend son soportadas.
la base de datos (o parte de ella) mediante objetos python (Tablas, columnas, constraints, etc...). • Puede emitir DDL statements, ej. crear todas las tablas modeladas en la base. • Extremadamente útil cuando es necesario inspeccionar la schema de la base, ej. encontrar todas las claves primarias en cada tabla. • Es posible también generar toda la metadata desde una estructura existente en la base de datos, esto es llamado reflection.
compuestos y generar SQL (strings) con el objetivo de ser ejecutadas por la base de datos, vía la engine y finalmente el adapter. • Estos objetos y las strings SQL que generan representan unidades de SQL, ej: una comparación, conjunciones, un update statement, etc... • Estas strings se pueden obtener fácilmente a partir de los objetos, lo cual es muy útil para debugging.
.select_from(users.outerjoin(addresses))) >>> print s SELECT users.user_name, addresses.email_address FROM users LEFT OUTER JOIN addresses ON users.id = addresses.user_id
presents a method of associating user-defined Python classes with database tables, and instances of those classes (objects) with rows in their corresponding tables.” • Visión de la data en el ORM enfocada en el domain model.
definir tablas y clases (llamadas normalmente modelos) y asociarlos. • Los ORMs modernos integran ambos pasos en uno. La tabla se genera a partir de la definición del modelo, sus atributos por ej. son convertidos en columnas • SQLAlchemy permite hacer todo explícitamente, crear una tabla como vimos anteriormente, un modelo y luego definir un mapper para asociar cada tabla con su modelo. • Y también provee una extensión, llamada declarative, que realiza esto automáticamente por nosotros.
Mapper, no Active Record. • Los detalles de la persistencia y el objeto a persistir se manejan de forma separada. >>> from sqlalchemy.orm import Session >>> s = Session() >>> user = User(username='gonz', email='[email protected]') >>> s.add(user) >>> user2 = s.query(User).filter(User.username == 'gonz').one() >>> user2.email = '[email protected]' >>> s.add(user2) >>> user is user2 True >>> s.commit()
cuenta de todo cuanto se hace en una transacción. • Cuando llega la hora de hacer un commit, organiza inserts/updates/deletes pendientes (Unit of work). • Esto le permite ordenar automáticamente statements según la dependencia topológica de las tablas y agrupar statements redundantes. • Mediante IdentityMaps cada instancia de un modelo en memoria es único, esto no solo ahorra memoria sino también consultas innecesarias a la base.