SQLAlchemy 和其他的 ORM 框架

来源:互联网 发布:网络女主播圈子很乱 编辑:程序博客网 时间:2024/06/03 20:55

Python ORM 概览

作为一个美妙的语言,Python 除了 SQLAlchemy 外还有很多ORM库。在这篇文章里,我们将来看看几个流行的可选 ORM 库,以此更好地窥探到Python ORM 境况。通过写一段脚本来读写2个表 ,person 和 address 到一个简单的数据库,我们能更好地理解每个ORM库的优缺点。

SQLObject

SQLObject 是一个介于SQL数据库和Python之间映射对象的Python ORM。得益于其类似于Ruby on Rails的ActiveRecord模式,在编程社区变得越来越流行。首个 SQLObject在2002年十月发布。它遵循LGPL许可。

在 SQLObject 中,数据库概念是通过与 SLQAlchemy 非常类似的的一种方式映射到Python的,表映射成类,行作为实例而字段作为属性。它同时提供一种基于Python对象的查询语言,这使得 SQL 更加抽象, 从而为应用提供了数据库不可知性(译注:应用和数据库分离)。

$ pip install sqlobjectDownloading/unpacking sqlobjectDownloading SQLObject-1.5.1.tar.gz (276kB): 276kB downloadedRunning setup.py egg_info for package sqlobject warning: no files found matching '*.html'warning: no files found matching '*.css'warning: no files found matching 'docs/*.html'warning: no files found matching '*.py' under directory 'tests'Requirement already satisfied (use --upgrade to upgrade): FormEncode>=1.1.1 in /Users/xiaonuogantan/python2-workspace/lib/python2.7/site-packages (from sqlobject)Installing collected packages: sqlobjectRunning setup.py install for sqlobjectchanging mode of build/scripts-2.7/sqlobject-admin from 644 to 755changing mode of build/scripts-2.7/sqlobject-convertOldURI from 644 to 755 warning: no files found matching '*.html'warning: no files found matching '*.css'warning: no files found matching 'docs/*.html'warning: no files found matching '*.py' under directory 'tests'changing mode of /Users/xiaonuogantan/python2-workspace/bin/sqlobject-admin to 755changing mode of /Users/xiaonuogantan/python2-workspace/bin/sqlobject-convertOldURI to 755Successfully installed sqlobjectCleaning up...


>>> from sqlobject import StringCol, SQLObject, ForeignKey, sqlhub, connectionForURI>>> sqlhub.processConnection = connectionForURI('sqlite:/:memory:')>>>>>> class Person(SQLObject):... name = StringCol()...>>> class Address(SQLObject):... address = StringCol()... person = ForeignKey('Person')...>>> Person.createTable()[]>>> Address.createTable()[]

上面的代码创建了2个简单的表:person 和 address 。为了创建和插入记录到这2个表,我们简单实例化一个person 实例和 一个 address 实例:
>>> p = Person(name='person')>>> a = Address(address='address', person=p)>>> p >>> a <address>
为了获得或检索新记录, 我们用神奇的 q 对象关联到 Person 和 Address 类:
>>> persons = Person.select(Person.q.name == 'person')>>> persons >>> list(persons)[]>>> p1 = persons[0]>>> p1 == pTrue>>> addresses = Address.select(Address.q.person == p1)>>> addresses >>> list(addresses)[ <address>]>>> a1 = addresses[0]>>> a1 == aTrue

Storm

Storm 是一个介于 单个或多个数据库与Python之间 映射对象的 Python ORM 。为了支持动态存储和取回对象信息,它允许开发者构建跨数据表的复杂查询。它由Ubuntu背后的公司 Canonical公司用Python开发的,用在 Launchpad 和 Landscape 应用中,后来在2007年作为自由软件发布。这个项目在LGPL许可下发布,代码贡献者必须受让版权给Canonical公司。

像 SQLAlchemy 和 SQLObject 那样, Storm 也映射表到类,行到实例和字段到属性。相对另外2个库, Stom中 table class 不需要是框架特定基类 的子类 。在 SQLAlchemy中,每个 table class 是 sqlalchemy.ext.declarative.declarative_bas 的一个子类。 而在SQLOjbect中,每个table class是 的 sqlobject.SQLObject 的子类。


类似于 SQLAlchemy, Storm 的 Store 对象对于后端数据库就像一个代理人, 所有的操作缓存在内存,一当提交方法在store上被调用就提交到数据库。每个 store 持有自己的Python数据库对象映射集合,就像一个 SQLAlchemy session 持有不同的 Python对象集合。

指定版本的 Storm 可以从 下载页面 下载。在这篇文章里,示例代码是使用 0.20 版本的Storm写的。

>>> from storm.locals import Int, Reference, Unicode, create_database, Store>>>>>>>>> db = create_database('sqlite:')>>> store = Store(db)>>>>>>>>> class Person(object):... __storm_table__ = 'person'... id = Int(primary=True)... name = Unicode()...>>>>>> class Address(object):... __storm_table__ = 'address'... id = Int(primary=True)... address = Unicode()... person_id = Int()... person = Reference(person_id, Person.id)...

上面的代码创建了一个 sqlite 内存数据库,然后用 store 来引用该数据库对象。一个Storm store 类似 SQLAlchemy的 DBSession对象,都管理 附属于其的实例对象 的生命周期。例如,下面的代码创建了一个 person 和 一个 address, 然后通过刷新 store 都插入记录。


>>> store.execute("CREATE TABLE person "... "(id INTEGER PRIMARY KEY, name VARCHAR)") >>> store.execute("CREATE TABLE address "... "(id INTEGER PRIMARY KEY, address VARCHAR, person_id INTEGER, "... " FOREIGN KEY(person_id) REFERENCES person(id))") >>> person = Person()>>> person.name = u'person'>>> print person >>> print "%r, %r" % (person.id, person.name)Noneu'person' # Notice that person.id is None since the Person instance is not attached to a valid database store yet.>>> store.add(person) >>> print "%r, %r" % (person.id, person.name)Noneu'person' # Since the store hasn't flushed the Person instance into the sqlite database yet, person.id is still None.>>> store.flush()>>> print "%r, %r" % (person.id, person.name)1u'person' # Now the store has flushed the Person instance, we got an id value for person.>>> address = Address()>>> address.person = person>>> address.address = 'address'>>> print "%r, %r, %r" % (address.id, address.person, address.address)None, , 'address'>>> address.person == personTrue>>> store.add(address) >>> store.flush()>>> print "%r, %r, %r" % (address.id, address.person, address.address)1, , 'address'

为了获得或检索已插的 Person 和 Address 对象, 我们调用 store.find() 来查询:

>>> person = store.find(Person, Person.name == u'person').one()>>> print "%r, %r" % (person.id, person.name)1u'person'>>> store.find(Address, Address.person == person).one() >>> address = store.find(Address, Address.person == person).one()>>> print "%r, %r" % (address.id, address.address)1u'address'

SQLAlchemy

 SQLAlchemy 是Python编程语言里,一个在MIT许可下发布的开源工具和SQL ORM。它首次发布于2006年二月,由Michael Bayer写的。它提供了 “一个知名企业级的持久化模式的,专为高效率和高性能的数据库访问设计的,改编成一个简单的Python域语言的完整套件”。它采用了数据映射模式(像Java中的Hibernate)而不是Active Record模式(像Ruby on Rails的ORM)。

SQLAlchemy 的工作单元 主要使得 有必要限制所有的数据库操作代码到一个特定的数据库session,在该session中控制每个对象的生命周期 。类似于其他的ORM,我们开始于定义declarative_base()的子类,以映射表到Python类。

>>> from sqlalchemy import Column, String, Integer, ForeignKey>>> from sqlalchemy.orm import relationship>>> from sqlalchemy.ext.declarative import declarative_base>>>>>>>>> Base = declarative_base()>>>>>>>>> class Person(Base):... __tablename__ = 'person'... id = Column(Integer, primary_key=True)... name = Column(String)...>>>>>> class Address(Base):... __tablename__ = 'address'... id = Column(Integer, primary_key=True)... address = Column(String)... person_id = Column(Integer, ForeignKey(Person.id))... person = relationship(Person)...


在我们写任何数据库代码前,我们需要为数据库session创建一个数据库引擎。

>>> from sqlalchemy import create_engine>>> engine = create_engine('sqlite:///')


一当我们创建了数据库引擎,可以继续创建一个数据库会话,并为所有之前定义的 Person和Address 类创建数据库表。

>>> from sqlalchemy.orm import sessionmaker>>> session = sessionmaker()>>> session.configure(bind=engine)>>> Base.metadata.create_all(engine)

现在,session 对象对象变成了我们工作单元的构造函数,将和所有后续数据库操作代码和对象关联到一个通过调用它的 __init__() 方法构建的数据库session上。

>>> s = session()>>> p = Person(name='person')>>> s.add(p)>>> a = Address(address='address', person=p)>>> s.add(a)

为了获得或检索数据库中的对象,我们在数据库session对象上调用 query() 和 filter() 方法。

>>> p = s.query(Person).filter(Person.name == 'person').one()>>> p >>> print "%r, %r" % (p.id, p.name)1'person'>>> a = s.query(Address).filter(Address.person == p).one()>>> print "%r, %r" % (a.id, a.address)1'address'

请留意到目前为止,我们还没有提交任何对数据库的更改,所以新的person和address对象实际上还没存储在数据库中。 调用 s.commit() 将会提交更改,比如,插入一个新的person和一个新的address到数据库中。

>>> s.commit()>>> s.close()



转自https://www.oschina.net/translate/sqlalchemy-vs-orms

原创粉丝点击