这可能看起来颇具争议性,但我刚刚浏览了SQLAlchemy的ORM tutorial并最终获得了以下代码:
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“更强大”,但这种力量似乎是有代价的,还是我错过了什么?
答案 0 :(得分:86)
嗯,有一件事你缺席:你提到的教程没有“构建”一个完整的例子,不同的代码片段并不意味着连接成一个源文件。相反,它们描述了可以使用库的不同方式。不需要自己一遍又一遍地尝试做同样的事情。
从示例中省略实际使用的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
而无需实际实例化它(如果当前线程中还没有一个会话,它将实例化一个新会话,或者重用现有的否则)
答案 1 :(得分: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作者elevator pitch在实践中保持良好状态。
答案 2 :(得分:1)
嗯,SQLAlchemy分为不同的部分,主要核心部分只是处理数据库,将python构建的查询转换为底层数据库的相应SQL语言。然后是对会话,orm和新的声明性语法的支持。
看起来像SQLObject(我不能肯定地说,多年没有使用它,即便如此,只有一次)跳过大部分内容并立即完成ORM部分。这通常会使简单数据变得更容易(在大多数情况下你可以使用它),但是SQLAlchemy允许更复杂的数据库布局,如果你真的需要它,可以使用数据库来解决这个问题。
答案 3 :(得分:1)
使用过SQLObject(并且只阅读了关于SQLAlchemy),我可以说SQLObject的优势之一就是可以轻松简单地完成任务。此外,电子邮件组(https://lists.sourceforge.net/lists/listinfo/sqlobject-discuss)提供了出色的支持,可以很快得到答案。
答案 4 :(得分: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一样简单。
答案 5 :(得分:0)
你说“复杂”......别人可能会说“灵活”。有时你需要它有时你不需要它。你有选择的不是很棒吗?