2009-05-13 12 views
30

Esto puede parece bastante controvertido, pero acaba de pasar por SQLAlchemy de ORM tutorial y terminó con el siguiente código:SQLAlchemy es intrincado?

from sqlalchemy import create_engine 
from sqlalchemy import Table, Column, Integer, String, MetaData, ForeignKey 
from sqlalchemy.ext.declarative import declarative_base 
from sqlalchemy.orm import sessionmaker 

engine = create_engine('sqlite:///:memory:', echo=True) 

metadata = MetaData() 
users_table = Table('users', metadata, 
    Column('id', Integer, primary_key=True), 
    Column('name', String), 
    Column('fullname', String), 
    Column('password', String) 
) 

metadata.create_all(engine) 

Base = declarative_base() 
class User(Base): 
    __tablename__ = 'users' 

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

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

    def __repr__(self): 
     return "<User('%s','%s', '%s')>" % (self.name, self.fullname, self.password) 

users_table = User.__table__ 
metadata = Base.metadata 

Session = sessionmaker(bind=engine) 
Session = sessionmaker() 
Session.configure(bind=engine) # once engine is available 
session = Session() 

# actually using the ORM isn't too bad.. 
ed_user = User('ed', 'Ed Jones', 'edspassword') 
session.add(ed_user) 

our_user = session.query(User).filter_by(name='ed').first() 
print our_user 

session.add_all([ 
    User('wendy', 'Wendy Williams', 'foobar'), 
    User('mary', 'Mary Contrary', 'xxg527'), 
    User('fred', 'Fred Flinstone', 'blah')]) 

ed_user.password = 'f8s7ccs' 

print session.dirty 
print session.new 
session.commit() 

for instance in session.query(User).order_by(User.id): 
    print instance.name, instance.fullname 

for name, fullname in session.query(User.name, User.fullname): 
    print name, fullname 

Esto parece muy complicado para efectivamente una mesa Hello World, especialmente en comparación con el código SQLObject más o menos similar:

from sqlobject import SQLObject, StringCol, sqlhub, connectionForURI 

sqlhub.processConnection = connectionForURI('sqlite:/:memory:') 

class Person(SQLObject): 
    fname = StringCol() 
    mi = StringCol(length=1, default=None) 
    lname = StringCol() 

Person.createTable() 

p = Person(fname="John", lname="Doe") 
p.mi = 'Q' 
p2 = Person.get(1) 
print p2 
print p2 is p 

entiendo SQLAlchemy es "más potente", pero que el poder parece tener un costo, o me estoy perdiendo algo?

+8

La potencia tiene un costo? ¿Qué estas diciendo? –

+12

¿El poder de SQLAlchemy se consigue a costa de la simplicidad de uso? – dbr

+3

Pruebe Elixir como se menciona a continuación, su Hello World será muy similar a SQLObject y aún podrá acceder a la capa SQLAlchemy. Usé SQLObject y me frustraron sus limitaciones, y estoy muy contento con Elixir hasta el momento (le falta un poco de documentación y soporte, pero la base de usuarios parece limitada por desgracia). –

Respuesta

85

Bueno, hay una cosa que te hace falta: el tutorial que mencionas no "compila" un ejemplo completo, los diferentes fragmentos de código no están destinados a concatenarse en un solo archivo fuente. Por el contrario, describen las diferentes formas en que se puede usar la biblioteca. No es necesario que intentes hacer lo mismo una y otra vez.

Dejando de lado la realidad-usando-el-orma parte de su ejemplo, el código podría tener este aspecto:

from sqlalchemy import * 
from sqlalchemy.ext.declarative import declarative_base 
from sqlalchemy.orm import sessionmaker, scoped_session 

engine = create_engine('sqlite:///:memory:', echo=True) 
Base = declarative_base(bind=engine) 
Session = scoped_session(sessionmaker(engine)) 

class User(Base): 
    __tablename__ = 'users' 

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

Base.metadata.create_all() 

La extensión "declarativa" se ocupa de la definición de la mesa y asignarla a su clase , por lo que no necesita declarar el users_table usted mismo. La clase de usuario también permitirá crear instancias con argumentos de palabras clave, como User(name="foo"), (aunque no con argumentos posicionales). También agregué el uso de scoped_session, lo que significa que puede usar directamente Session sin tener que crear una instancia (creará una nueva sesión si no hay una presente en el hilo actual, o reutilizará la existente)

+2

Eso se ve un poco más sensible que el código con el que terminé. ¡Gracias! – dbr

+1

Tengo muchas dudas sobre el uso de 'scoped_session' para cualquier cosa; A menos que sepa por qué necesita el almacenamiento local de subprocesos, debe crear una instancia de la sesión explícitamente y pasarla según sea necesario. – SingleNegationElimination

+1

@TokenMacGuy No estoy de acuerdo por completo. 'scoped_session' toma todas las conjeturas y argumentos innecesarios que pasan fuera del uso de sesiones. Simplemente defina su clase 'scoped_session' al comienzo, luego ejecútelo donde sea que necesite acceder a la sesión, y el sistema hace el resto. He encontrado que es extremadamente útil para todas las aplicaciones web que he escrito. – CoreDumpError

0

dices "enrevesado" ... alguien más puede decir "flexible". A veces lo necesitas a veces no. ¿No es asombroso que tengas elección?

+0

Claro, pero digo "enrevesado" porque parece forzarte a usar muchas de sus funciones para hacer cosas básicas. La flexibilidad es excelente, pero no si se trata de cinco líneas de importación para comenzar. – dbr

1

Bueno, SQLAlchemy se divide en diferentes partes, la parte central principal simplemente maneja la base de datos, transformando las consultas creadas por python en el lenguaje SQL apropiado para la base de datos subyacente. Luego está el soporte para sesiones, el orm y la nueva sintaxis declarativa.

Parece SQLObject (no puedo asegurarlo, no lo he usado en muchos años, y aun así, solo una vez) se salta la mayor parte y lo hace directamente. Esto a menudo facilita las cosas con datos simples (que en la mayoría de los casos puedes salirte con la tuya), pero SQLAlchemy permite diseños de bases de datos más complejos y se vuelve sucio con el archivo db si realmente lo necesitas.

+0

Parece que SQLObject admite cosas más avanzadas, como las relaciones uno a muchos/muchos a uno/muchos a muchos (que cubren todos los diseños de bases de datos que he visto) y las transacciones. – dbr

10

Los ejemplos de código que usted da no son manzanas con manzanas. La versión SQLAlchemy podría ser pelado abajo un poco:

from sqlalchemy import create_engine 
from sqlalchemy import Table, Column, Integer, String, MetaData, ForeignKey 
from sqlalchemy.ext.declarative import declarative_base 
from sqlalchemy.orm import sessionmaker 

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

class User(Base): 
    __tablename__ = 'users' 

    id = Column('id', Integer, primary_key=True) 
    name = Column('name', String) 
    fullname = Column('fullname', String) 
    password = Column('password', String) 

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

Base.metadata.create_all(engine) 

Session = sessionmaker(bind=engine) 
session = Session() 

# actually using the ORM isn't too bad.. 
ed_user = User(name='ed', fullname='Ed Jones', password='edspassword') 
session.add(ed_user) 

our_user = session.query(User).filter_by(name='ed').first() 

session.add_all([ 
    User(name='wendy', fullname='Wendy Williams', password='foobar'), 
    User(name='mary', fullname='Mary Contrary', password='xxg527'), 
    User(name='fred', fullname='Fred Flinstone', password='blah')]) 

ed_user.password = 'f8s7ccs' 

session.flush() 

for instance in session.query(User).order_by(User.id): 
    print instance.name, instance.fullname 

for name, fullname in session.query(User.name, User.fullname): 
    print name, fullname 

También puede encontrar Elixir más como SQLObject (pero ya que no he utilizado, ya sea, eso es sólo una conjetura).

Al no haber usado SQLObject en absoluto, no puedo hacer ningún comentario sobre qué es exactamente lo que SA hace mejor. Pero he tenido grandes experiencias con SA, especialmente cuando se trata de esquemas heredados complicados del mundo real. Hace un buen trabajo al generar buenas consultas SQL de manera predeterminada, y tiene muchas formas de ajustarlas.

He encontrado que elevator pitch del autor de SQLAlchemy se sostiene bastante bien en la práctica.

1

Al haber utilizado SQLObject (y solo he leído sobre SQLAlchemy), puedo decir que uno de los puntos fuertes de SQLObject es la facilidad y simplicidad con la que puede hacer las cosas.Además, el grupo de correo electrónico (https://lists.sourceforge.net/lists/listinfo/sqlobject-discuss) brinda una excelente asistencia que le da respuestas rápidamente.

1

Trate Quick ORM, es aún más simple:

from quick_orm.core import Database 
from sqlalchemy import Column, String 

class User(object): 
    __metaclass__ = Database.DefaultMeta 
    name = Column(String(30)) 

if __name__ == '__main__': 
    database = Database('sqlite://') 
    database.create_tables() 

    user = User(name = 'Hello World') 
    database.session.add_then_commit(user) 

    user = database.session.query(User).get(1) 
    print 'My name is', user.name 

Quick ORM se basa en SQLAlchemy, por lo que podríamos decir que SQLAlchemy podría ser tan simple como SQLObject.

+0

Lamento que quick_orm ya no se mantenga. –