36

这似乎很有争议,但我刚刚浏览了 SQLAlchemy 的ORM 教程并最终得到以下代码:

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

对于有效的 Hello World 表来说,这似乎非常复杂,尤其是与大致相似的 SQLObject 代码相比:

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

我知道 SQLAlchemy “更强大”,但这种能力似乎是有代价的,还是我错过了什么?

4

6 回答 6

88

好吧,您缺少一件事:您提到的教程并没有“构建”一个完整的示例,不同的代码片段并不意味着要连接到一个源文件中。相反,它们描述了可以使用该库的不同方式。无需自己一遍又一遍地尝试做同样的事情。

从您的示例中省略实际使用的orm部分,代码可能如下所示:

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()

“声明性”扩展负责定义表并将其映射到您的类,因此您不需要users_table自己声明。User 类还将允许使用关键字参数进行实例化,例如User(name="foo"),(但不是位置参数)。我还添加了对 scoped_session 的使用,这意味着您可以直接使用Session而无需实际实例化它(如果当前线程中还没有会话,它将实例化一个新会话,否则重用现有会话)

于 2009-05-13T21:52:41.983 回答
10

您提供的代码示例不是苹果对苹果。SQLAlchemy 版本可以减少一点:

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

您可能还会发现Elixir更像 SQLObject(但由于我没有使用过任何一种,这只是一个猜测)。

根本没有使用过 SQLObject,我无法评论 SA 究竟在哪些方面做得更好。但我在 SA 方面拥有丰富的经验,尤其是在处理复杂的、现实世界的遗留模式时。默认情况下,它很好地提出了良好的 SQL 查询,并且有很多方法可以调整它们。

我发现 SQLAlchemy 作者的电梯间距在实践中表现得很好。

于 2009-05-13T21:53:11.920 回答
1

好吧,SQLAlchemy 分为不同的部分,主要核心部分只是处理数据库,将您的 python 构建查询转换为底层数据库的适当 SQL 语言。然后是对会话、orm 和新的声明性语法的支持。

看起来 SQLObject (我不能肯定地说,已经很多年没有使用它了,即使那样,也只有一次)跳过了大部分并立即执行 ORM 部分。这通常使简单数据的事情变得更容易(在大多数情况下你可以逃脱),但 SQLAlchemy 允许更复杂的数据库布局,如果你真的需要它,可以使用数据库。

于 2009-05-13T21:05:04.620 回答
1

使用过 SQLObject(并且只阅读过 SQLAlchemy),我可以说 SQLObject 的优势之一是您可以轻松简单地完成工作。此外,电子邮件组 ( https://lists.sourceforge.net/lists/listinfo/sqlobject-discuss ) 提供了出色的支持,可以很快地回复您。

于 2009-05-13T22:04:53.383 回答
1

试试Quick ORM,它更简单:

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建立在 SQLAlchemy 之上,因此我们可以说 SQLAlchemy 可以像 SQLObject 一样简单。

于 2011-11-11T18:53:42.600 回答
0

您说“令人费解”....其他人可能会说“灵活”。有时你需要它,有时你不需要。你有选择权不是很棒吗?

于 2009-05-13T20:58:36.487 回答