SqlSoup, mapeo de bases de datos a python con SqlAlchemy

danigm's picture

El otro día un amigo me preguntó como hacer consultas a una base de datos mysql desde python y le comenté que con sqlalchemy se podía hacer. Yo ya había hecho algunas cosas con sqlalchemy, pero no había tratado con bases de datos ya creadas, sino que siempre las creaba con sqlalchemy.

He estado mirando un poco en la web de sqlalchemy y me he encontrado SqlSoup (SqlAlchemy).

SqlSoup mapea una base de datos ya creada a objetos python, así que no es necesario crear las clases o declarar las tablas en código python, se infieren directamente de la base de datos ya creada.

Veamos como funciona con un simple ejemplo con sqlite.

  1. Creamos la base de datos sqlite para las pruebas

  2. [c]
    $ sqlite3 testdb.sqlite
    sqlite> create table users (name varchar(50), email varchar(100), primary key (name));
    sqlite> create table posts (id integer not_null auto_increment, user_id varchar(50),
    ...> text varchar, primary key (id), foreign key (user_id) references users(name));
    [/c]

  3. Aquí un script de prueba para ejecutar

  4. [python]
    # http://www.sqlalchemy.org/docs/05/reference/ext/sqlsoup.html
    # Mapeando una base de datos ya creada para usar desde python de
    # manera simple y rapida.

    # creamos la base de datos con sqlite3
    # sqlite3 testdb.sqlite
    # sqlite> create table users (name varchar(50), email varchar(100), primary key (name));
    # sqlite> create table posts (id integer not_null auto_increment, user_id varchar(50),
    # ...> text varchar, primary key (id), foreign key (user_id) references users(name));

    from sqlalchemy.ext.sqlsoup import SqlSoup, Session
    from sqlalchemy import or_, and_, desc

    #db = SqlSoup('mysql://scott:tiger@localhost/mydatabase')
    db = SqlSoup('sqlite:///testdb.sqlite')

    def add_users():
    user = db.users.insert(name='danigm', email='dani@exp.com')
    user2 = db.users.insert(name='dani', email='danigm@exp.com')
    user3 = db.users.insert(name='pepe', email='pepe@exp.com')
    user4 = db.users.insert(name='juan', email='juan@exp.com')

    db.flush()
    Session.commit()

    def add_posts():
    post1 = db.posts.insert(id=1, user_id='danigm', text='comentario1')
    post2 = db.posts.insert(id=2, user_id='danigm', text='comentario2')
    post3 = db.posts.insert(id=3, user_id='pepe', text='comentario3')
    post4 = db.posts.insert(id=4, user_id='juan', text='comentario4')
    db.flush()
    Session.commit()

    try:
    add_users()
    except:
    Session.rollback()
    try:
    add_posts()
    except:
    Session.rollback()

    print db.users.filter(db.users.name=='danigm').first().name

    where = or_(db.users.name=='danigm',
    db.users.email=='danigm@exp.com')

    users = db.users.filter(where).order_by(desc(db.users.name)).all()
    print users

    user = users[0]
    for post in db.posts.filter(db.posts.user_id == user.name):
    print user.name, post.text

    [/python]

  5. Veamoslo paso a paso

  6. [python]
    db = SqlSoup('sqlite:///testdb.sqlite')
    [/python]
    Con esta simple línea tenemos el objeto db que está conectado con la base de datos y ya podemos empezar a hacer consultas u otras cosas.

    [python]
    user = db.users.insert(name='danigm', email='dani@danigm.net')
    db.flush()
    Session.commit()
    [/python]
    Podemos acceder a las tablas por su nombre directamente, db.users, db.posts y estos objetos tienen métodos para insertar, borrar o filtrar de tal forma que podamos hacer la consulta deseada, en este ejemplo añadimos un usuario. Hay que tener en cuenta que para que los cambios se vean reflejados hay que ejecutar el commit().

    [python]
    print db.users.filter(db.users.name=='danigm').first().name
    [/python]
    se puede filtrar como en cualquier objeto de sqlite, en este ejemplo filtramos por nombre de usuario, nos quedamos con el primero y mostramos el nombre del mismo.

    [python]
    where = or_(db.users.name=='danigm',
    db.users.email=='danigm@exp.com')

    users = db.users.filter(where).order_by(desc(db.users.name)).all()
    print users

    user = users[0]
    for post in db.posts.filter(db.posts.user_id == user.name):
    print user.name, post.text
    [/python]
    Y una vez dominado el uso de sqlalchemy se pueden hacer filtros más complejos con otras directivas. combinando filtros y usando toda la potencia que te da sqlalchemy.

Con este ejemplo vemos que acceder a bases de datos desde python es muy fácil con sqlalchemy y además puedes hacerlo independiente del motor de base de datos gracias a que sqlalchemy soporta mysql, postgresql, sqlite, oracle, firebird, MS-SQL, MSAccess.

Comments

4
David's picture

Gracias por este post, me sera de mucha ayuda! eres un crare

David's picture

una cosa es que no quieras que escriban bots y otra los captchas que pones!! he tenido que escribir 3 para acertar.

danigm's picture

He cambiado un poco el capcha este, los puntitos de colores lo mismo metían mucho ruido :P

shakaran's picture

Creo que puedes mejorar el código un poco más haciéndolo más pythonico y utilizando bucles for a modo de iterador para insertar los usuarios, por ejemplo:

def add_users():
for (name, email) in [('danigm','dani@exp.com'),('dani','danigm@exp.com'),('pepe','pepe@exp.com'),('juan','juan@exp.com'),]
db.users.insert(name, email)

db.flush()
Session.commit()

Lo mismo en otras partes del código ;) Buen ejemplo, me será útil.