日韩久久久精品,亚洲精品久久久久久久久久久,亚洲欧美一区二区三区国产精品 ,一区二区福利

在Python的Django框架上部署ORM庫的教程

系統(tǒng) 1883 0

Python ORM 概覽

作為一個(gè)美妙的語言,Python 除了 SQLAlchemy 外還有很多ORM庫。在這篇文章里,我們將來看看幾個(gè)流行的可選ORM 庫,以此更好地窺探到Python ORM 境況。通過寫一段腳本來讀寫2個(gè)表 ,person 和 address 到一個(gè)簡單的數(shù)據(jù)庫,我們能更好地理解每個(gè)ORM庫的優(yōu)缺點(diǎn)。

SQLObject

SQLObject 是一個(gè)介于SQL數(shù)據(jù)庫和Python之間映射對(duì)象的Python ORM。得益于其類似于Ruby on Rails的ActiveRecord模式,在編程社區(qū)變得越來越流行。首個(gè) SQLObject在2002年十月發(fā)布。它遵循LGPL許可。

在 SQLObject 中,數(shù)據(jù)庫概念是通過與 SLQAlchemy 非常類似的的一種方式映射到Python的,表映射成類,行作為實(shí)例而字段作為屬性。它同時(shí)提供一種基于Python對(duì)象的查詢語言,這使得SQL 更加抽象, 從而為應(yīng)用提供了數(shù)據(jù)庫不可知性(譯注:應(yīng)用和數(shù)據(jù)庫分離)
?

            
$ pip install sqlobject
Downloading/unpacking sqlobject
Downloading SQLObject-1.5.1.tar.gz (276kB): 276kB downloaded
Running 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: sqlobject
Running setup.py install for sqlobject
changing mode of build/scripts-2.7/sqlobject-admin from 644 to 755
changing 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 755
changing mode of /Users/xiaonuogantan/python2-workspace/bin/sqlobject-convertOldURI to 755
Successfully installed sqlobject
Cleaning 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()
[]

          

上面的代碼創(chuàng)建了2個(gè)簡單的表:person 和 address 。為了創(chuàng)建和插入記錄到這2個(gè)表,我們簡單實(shí)例化一個(gè)person 實(shí)例和 一個(gè) address 實(shí)例:
?

            
>>> p = Person(name='person')
>>> a = Address(address='address', person=p)
>>> p
 
>>> a
 

            

為了獲得或檢索新記錄, 我們用神奇的 q 對(duì)象關(guān)聯(lián)到 Person 和 Address 類:

?

            
>>> persons = Person.select(Person.q.name == 'person')
>>> persons
 
>>> list(persons)
[]
>>> p1 = persons[0]
>>> p1 == p
True
>>> addresses = Address.select(Address.q.person == p1)
>>> addresses
 
>>> list(addresses)
[
 

            
] >>> a1 = addresses[0] >>> a1 == a True Storm

Storm 是一個(gè)介于 單個(gè)或多個(gè)數(shù)據(jù)庫與Python之間 映射對(duì)象的 Python ORM 。為了支持動(dòng)態(tài)存儲(chǔ)和取回對(duì)象信息,它允許開發(fā)者構(gòu)建跨數(shù)據(jù)表的復(fù)雜查詢。它由Ubuntu背后的公司 Canonical公司用Python開發(fā)的,用在 Launchpad 和 Landscape 應(yīng)用中,后來在2007年作為自由軟件發(fā)布。這個(gè)項(xiàng)目在LGPL許可下發(fā)布,代碼貢獻(xiàn)者必須受讓版權(quán)給Canonical公司。

像 SQLAlchemy 和 SQLObject 那樣, Storm 也映射表到類,行到實(shí)例和字段到屬性。相對(duì)另外2個(gè)庫, Stom中 table class 不需要是框架特定基類 的子類 。在 SQLAlchemy中,每個(gè) table class 是 sqlalchemy.ext.declarative.declarative_bas 的一個(gè)子類。 而在SQLOjbect中,每個(gè)table class是 的 sqlobject.SQLObject 的子類。
?

類似于 SQLAlchemy, Storm 的 Store 對(duì)象對(duì)于后端數(shù)據(jù)庫就像一個(gè)代理人, 所有的操作緩存在內(nèi)存,一當(dāng)提交方法在store上被調(diào)用就提交到數(shù)據(jù)庫。每個(gè) store 持有自己的Python數(shù)據(jù)庫對(duì)象映射集合,就像一個(gè) SQLAlchemy session 持有不同的 Python對(duì)象集合。

指定版本的 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)
...

          

上面的代碼創(chuàng)建了一個(gè) sqlite 內(nèi)存數(shù)據(jù)庫,然后用 store 來引用該數(shù)據(jù)庫對(duì)象。一個(gè)Storm store 類似 SQLAlchemy的 DBSession對(duì)象,都管理 附屬于其的實(shí)例對(duì)象 的生命周期。例如,下面的代碼創(chuàng)建了一個(gè) person 和 一個(gè) 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)
None, u'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)
None, u'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)
1, u'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 == person
True
>>> store.add(address)
 
>>> store.flush()
>>> print "%r, %r, %r" % (address.id, address.person, address.address)
1, , 'address'

          

為了獲得或檢索已插的 Person 和 Address 對(duì)象, 我們調(diào)用 store.find() 來查詢:

?

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

          

Django 的 ORM

Django 是一個(gè)免費(fèi)開源的緊嵌ORM到其系統(tǒng)的web應(yīng)用框架。在它首次發(fā)布后,得益于其易用為Web而備的特點(diǎn),Django越來越流行。它在2005年七月在BSD許可下發(fā)布。因?yàn)镈jango的ORM 是緊嵌到web框架的,所以就算可以也不推薦,在一個(gè)獨(dú)立的非Django的Python項(xiàng)目中使用它的ORM。

Django,一個(gè)最流行的Python web框架, 有它獨(dú)有的 ORM。 相比 SQLAlchemy, Django 的 ORM 更吻合于直接操作SQL對(duì)象,操作暴露了簡單直接映射數(shù)據(jù)表和Python類的SQL對(duì)象 。

?

            
$ django-admin.py startproject demo
$ cd demo
$ python manage.py syncdb
Creating tables ...
Creating table django_admin_log
Creating table auth_permission
Creating table auth_group_permissions
Creating table auth_group
Creating table auth_user_groups
Creating table auth_user_user_permissions
Creating table auth_user
Creating table django_content_type
Creating table django_session
 
You just installed Django's auth system, which means you don't have any superusers defined.
Would you like to create one now? (yes/no): no
Installing custom SQL ...
Installing indexes ...
Installed 0 object(s) from 0 fixture(s)
$ python manage.py shell

          

因?yàn)槲覀冊(cè)跊]有先建立一個(gè)項(xiàng)目時(shí)不能夠執(zhí)行Django代碼,所以我們?cè)谇懊娴膕hell創(chuàng)建一個(gè)Django demo 項(xiàng)目,然后進(jìn)入Django shell來測(cè)試我們寫的 ORM 例子。

?

            
# demo/models.py
>>> from django.db import models
>>>
>>>
>>> class Person(models.Model):
... name = models.TextField()
... class Meta:
... app_label = 'demo'
...
>>>
>>> class Address(models.Model):
... address = models.TextField()
... person = models.ForeignKey(Person)
... class Meta:
... app_label = 'demo'
...

          

上面的代碼聲明了2個(gè)Python 類,Person 和 Address,每一個(gè)都映射到數(shù)據(jù)庫表。在執(zhí)行任意數(shù)據(jù)庫操作代碼之前,我們需要先在本地的sqlite數(shù)據(jù)庫創(chuàng)建表。

            
python manage.py syncdb
Creating tables ...
Creating table demo_person
Creating table demo_address
Installing custom SQL ...
Installing indexes ...
Installed 0 object(s) from 0 fixture(s)


          

為了插入一個(gè) person 和一個(gè) address 到數(shù)據(jù)庫,我們實(shí)例化相應(yīng)對(duì)象并調(diào)用這些對(duì)象的save() 方法。
?

            
>>> from demo.models import Person, Address
>>> p = Person(name='person')
>>> p.save()
>>> print "%r, %r" % (p.id, p.name)
1, 'person'
>>> a = Address(person=p, address='address')
>>> a.save()
>>> print "%r, %r" % (a.id, a.address)
1, 'address'

          

為了獲得或檢索 person 和 address 對(duì)象, 我們用model類神奇的對(duì)象屬性從數(shù)據(jù)庫取得對(duì)象。
?

            
>>> persons = Person.objects.filter(name='person')
>>> persons
[]
>>> p = persons[0]
>>> print "%r, %r" % (p.id, p.name)
1, u'person'
>>> addresses = Address.objects.filter(person=p)
>>> addresses
[
 

            
] >>> a = addresses[0] >>> print "%r, %r" % (a.id, a.address) 1, u'address'

peewee

peewee 是一個(gè)小的,表達(dá)式的 ORM。相比其他的 ORM,peewee 主要專注于極簡主義,其API簡單,并且其庫容易使用和理解。
?

            
pip install peewee
Downloading/unpacking peewee
Downloading peewee-2.1.7.tar.gz (1.1MB): 1.1MB downloaded
Running setup.py egg_info for package peewee
 
Installing collected packages: peewee
Running setup.py install for peewee
changing mode of build/scripts-2.7/pwiz.py from 644 to 755
 
changing mode of /Users/xiaonuogantan/python2-workspace/bin/pwiz.py to 755
Successfully installed peewee
Cleaning up...

          

為了創(chuàng)建數(shù)據(jù)庫模型映射,我們實(shí)現(xiàn)了一個(gè)Person 類 和一個(gè)Address類 來映射對(duì)應(yīng)的數(shù)據(jù)庫表。

?

            
>>> from peewee import SqliteDatabase, CharField, ForeignKeyField, Model
>>>
>>> db = SqliteDatabase(':memory:')
>>>
>>> class Person(Model):
... name = CharField()
... class Meta:
... database = db
...
>>>
>>> class Address(Model):
... address = CharField()
... person = ForeignKeyField(Person)
... class Meta:
... database = db
...
>>> Person.create_table()
>>> Address.create_table()

          

為了插入對(duì)象到數(shù)據(jù)庫,我們實(shí)例化對(duì)象并調(diào)用了它們的save() 方法。從視圖的對(duì)象創(chuàng)建這點(diǎn)來看,peewee類似于Django。
?

            
>>> p = Person(name='person')
>>> p.save()
>>> a = Address(address='address', person=p)
>>> a.save()

          

為了從數(shù)據(jù)庫獲得或檢索對(duì)象, 我們select 了類各自的對(duì)象。

?

            
>>> person = Person.select().where(Person.name == 'person').get()
>>> person
 
>>> print '%r, %r' % (person.id, person.name)
1, u'person'
>>> address = Address.select().where(Address.person == person).get()
>>> print '%r, %r' % (address.id, address.address)
1, u'address'

          

SQLAlchemy

?SQLAlchemy 是Python編程語言里,一個(gè)在MIT許可下發(fā)布的開源工具和SQL ORM。它首次發(fā)布于2006年二月,由Michael Bayer寫的。它提供了 “一個(gè)知名企業(yè)級(jí)的持久化模式的,專為高效率和高性能的數(shù)據(jù)庫訪問設(shè)計(jì)的,改編成一個(gè)簡單的Python域語言的完整套件”。它采用了數(shù)據(jù)映射模式(像Java中的Hibernate)而不是Active Record模式(像Ruby on Rails的ORM)。

SQLAlchemy 的工作單元 主要使得 有必要限制所有的數(shù)據(jù)庫操作代碼到一個(gè)特定的數(shù)據(jù)庫session,在該session中控制每個(gè)對(duì)象的生命周期 。類似于其他的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)
...

          

在我們寫任何數(shù)據(jù)庫代碼前,我們需要為數(shù)據(jù)庫session創(chuàng)建一個(gè)數(shù)據(jù)庫引擎。
?

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

          

一當(dāng)我們創(chuàng)建了數(shù)據(jù)庫引擎,可以繼續(xù)創(chuàng)建一個(gè)數(shù)據(jù)庫會(huì)話,并為所有之前定義的 Person和Address 類創(chuàng)建數(shù)據(jù)庫表。
?

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

          

現(xiàn)在,session 對(duì)象對(duì)象變成了我們工作單元的構(gòu)造函數(shù),將和所有后續(xù)數(shù)據(jù)庫操作代碼和對(duì)象關(guān)聯(lián)到一個(gè)通過調(diào)用它的 __init__() 方法構(gòu)建的數(shù)據(jù)庫session上。
?

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

          

為了獲得或檢索數(shù)據(jù)庫中的對(duì)象,我們?cè)跀?shù)據(jù)庫session對(duì)象上調(diào)用 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'

          

請(qǐng)留意到目前為止,我們還沒有提交任何對(duì)數(shù)據(jù)庫的更改,所以新的person和address對(duì)象實(shí)際上還沒存儲(chǔ)在數(shù)據(jù)庫中。 調(diào)用 s.commit() 將會(huì)提交更改,比如,插入一個(gè)新的person和一個(gè)新的address到數(shù)據(jù)庫中。
?

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

          

Python ORM 之間對(duì)比

對(duì)于在文章里提到的每一種 Python ORM ,我們來列一下他們的優(yōu)缺點(diǎn):
SQLObject

優(yōu)點(diǎn):

  • ??? 采用了易懂的ActiveRecord 模式
  • ??? 一個(gè)相對(duì)較小的代碼庫

缺點(diǎn):

  • ??? 方法和類的命名遵循了Java 的小駝峰風(fēng)格
  • ??? 不支持?jǐn)?shù)據(jù)庫session隔離工作單元


Storm

優(yōu)點(diǎn):

  • ??? 清爽輕量的API,短學(xué)習(xí)曲線和長期可維護(hù)性
  • ??? 不需要特殊的類構(gòu)造函數(shù),也沒有必要的基類

缺點(diǎn):

  • ??? 迫使程序員手工寫表格創(chuàng)建的DDL語句,而不是從模型類自動(dòng)派生
  • ??? Storm的貢獻(xiàn)者必須把他們的貢獻(xiàn)的版權(quán)給Canonical公司


Django's ORM

優(yōu)點(diǎn):

  • ??? 易用,學(xué)習(xí)曲線短
  • ??? 和Django緊密集合,用Django時(shí)使用約定俗成的方法去操作數(shù)據(jù)庫

缺點(diǎn):

  • ??? 不好處理復(fù)雜的查詢,強(qiáng)制開發(fā)者回到原生SQL
  • ??? 緊密和Django集成,使得在Django環(huán)境外很難使用


peewee

優(yōu)點(diǎn):

  • ??? Django式的API,使其易用
  • ??? 輕量實(shí)現(xiàn),很容易和任意web框架集成

缺點(diǎn):

  • ??? 不支持自動(dòng)化 schema 遷移
  • ??? 多對(duì)多查詢寫起來不直觀


SQLAlchemy

優(yōu)點(diǎn):

  • ??? 企業(yè)級(jí) API,使得代碼有健壯性和適應(yīng)性
  • ??? 靈活的設(shè)計(jì),使得能輕松寫復(fù)雜查詢

缺點(diǎn):

  • ??? 工作單元概念不常見
  • ??? 重量級(jí) API,導(dǎo)致長學(xué)習(xí)曲線


總結(jié)和提示

相比其他的ORM, SQLAlchemy 意味著,無論你何時(shí)寫SQLAlchemy代碼, 都專注于工作單元的前沿概念 。DB Session 的概念可能最初很難理解和正確使用,但是后來你會(huì)欣賞這額外的復(fù)雜性,這讓意外的時(shí)序提交相關(guān)的數(shù)據(jù)庫bug減少到0。在SQLAlchemy中處理多數(shù)據(jù)庫是棘手的, 因?yàn)槊總€(gè)DB session 都限定了一個(gè)數(shù)據(jù)庫連接。但是,這種類型的限制實(shí)際上是好事, 因?yàn)檫@樣強(qiáng)制你絞盡腦汁去想在多個(gè)數(shù)據(jù)庫之間的交互, 從而使得數(shù)據(jù)庫交互代碼很容易調(diào)試。

在未來的文章中,我們將會(huì)完整地披露更高階的SQLAlchemy用例, 真正領(lǐng)會(huì)無限強(qiáng)大的API。


更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號(hào)聯(lián)系: 360901061

您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長非常感激您!手機(jī)微信長按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對(duì)您有幫助就好】

您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺我的文章對(duì)您有幫助,請(qǐng)用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長會(huì)非常 感謝您的哦!!!

發(fā)表我的評(píng)論
最新評(píng)論 總共0條評(píng)論
主站蜘蛛池模板: 建瓯市| 晋城| 江安县| 开平市| 灵石县| 海原县| 上栗县| 太白县| 福鼎市| 鄱阳县| 肇源县| 琼结县| 凯里市| 友谊县| 蚌埠市| 巴东县| 临汾市| 句容市| 商南县| 缙云县| 仙居县| 通许县| 光山县| 固安县| 昭觉县| 六枝特区| 洞口县| 仁寿县| 北宁市| 惠东县| 枝江市| 福州市| 天祝| 阳城县| 临西县| 浦北县| 肇东市| 靖西县| 比如县| 平和县| 措勤县|