西西軟件園多重安全檢測(cè)下載網(wǎng)站、值得信賴的軟件下載站!
軟件
軟件
文章
搜索

首頁(yè)編程開(kāi)發(fā)其它知識(shí) → sqlalchemy中文文檔 sqlalchemy中文手冊(cè)

sqlalchemy中文文檔 sqlalchemy中文手冊(cè)

相關(guān)軟件相關(guān)文章發(fā)表評(píng)論 來(lái)源:西西整理時(shí)間:2017/10/29 10:06:47字體大小:A-A+

作者:西西點(diǎn)擊:0次評(píng)論:0次標(biāo)簽: sqlalchemy sqlalchemy中文

psycopg22.7.3.2 官方最新版
  • 類型:運(yùn)動(dòng)健身大。3.5M語(yǔ)言:中文 評(píng)分:5.0
  • 標(biāo)簽:
立即下載

SQLAlchemy 連接到關(guān)系型數(shù)據(jù)庫(kù),關(guān)系型數(shù)據(jù)最擅長(zhǎng)的東西就是關(guān)系。SQLAlchemy是Python編程語(yǔ)言下的一款開(kāi)源軟件。提供了SQL工具包及對(duì)象關(guān)系映射(ORM)工具,使用MIT許可證發(fā)行。

1.版本檢查

import sqlalchemy
sqlalchemy.__version__

2.連接

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

echo參數(shù)為T(mén)rue時(shí),會(huì)顯示每條執(zhí)行的SQL語(yǔ)句,可以關(guān)閉。create_engine()返回一個(gè)Engine的實(shí)例,并且它表示通過(guò)數(shù)據(jù)庫(kù)語(yǔ)法處理細(xì)節(jié)的核心接口,在這種情況下,數(shù)據(jù)庫(kù)語(yǔ)法將會(huì)被解釋稱Python的類方法。

3.聲明映像

當(dāng)使用ORM【1】時(shí),構(gòu)造進(jìn)程首先描述數(shù)據(jù)庫(kù)的表,然后定義我們用來(lái)映射那些表的類。在現(xiàn)版本的SQLAlchemy中,這兩個(gè)任務(wù)通常一起執(zhí)行,通過(guò)使用Declarative方法,我們可以創(chuàng)建一些包含描述要被映射的實(shí)際數(shù)據(jù)庫(kù)表的準(zhǔn)則的映射類。

使用Declarative方法定義的映射類依據(jù)一個(gè)基類,這個(gè)基類是維系類和數(shù)據(jù)表關(guān)系的目錄——我們所說(shuō)的Declarative base class。在一個(gè)普通的模塊入口中,應(yīng)用通常只需要有一個(gè)base的實(shí)例。我們通過(guò)declarative_base()功能創(chuàng)建一個(gè)基類:

from sqlalchemy.ext.declarativeimportdeclarative_base
Base = declarative_base()

有了這個(gè)base,我們可以依據(jù)這個(gè)base定義任意數(shù)量的映射類。一個(gè)簡(jiǎn)單的user例子:

from sqlalchemy import Column, Integer, String
class User(Base):
__tablename__= 'users'
id= Column(Integer, primary_key=True)
name = Column(String)

用Declarative構(gòu)造的一個(gè)類至少需要一個(gè)__tablename__屬性,一個(gè)主鍵行。

4.構(gòu)造模式(項(xiàng)目中沒(méi)用到)

5.創(chuàng)建映射類的實(shí)例

ed_user = User(name='ed',fullname='Ed Jones', password='edspassword')

6.創(chuàng)建會(huì)話

現(xiàn)在我們已經(jīng)準(zhǔn)備毫和數(shù)據(jù)庫(kù)開(kāi)始會(huì)話了。ORM通過(guò)Session與數(shù)據(jù)庫(kù)建立連接的。當(dāng)應(yīng)用第一次載入時(shí),我們定義一個(gè)Session類(聲明create_engine()的同時(shí)),這個(gè)Session類為新的Session對(duì)象提供工廠服務(wù)。

from sqlalchemy.orm import sessionmaker
Session = sessionmaker(bind=engine)

這個(gè)定制的Session類會(huì)創(chuàng)建綁定到數(shù)據(jù)庫(kù)的Session對(duì)象。如果需要和數(shù)據(jù)庫(kù)建立連接,只需要實(shí)例化一個(gè)Session:

session = Session()

雖然上面的Session已經(jīng)和數(shù)據(jù)庫(kù)引擎Engine關(guān)聯(lián),但是還沒(méi)有打開(kāi)任何連接。當(dāng)它第一次被使用時(shí),就會(huì)從Engine維護(hù)的一個(gè)連接池中檢索是否存在連接,如果存在便會(huì)保持連接知道我們提交所有更改并且/或者關(guān)閉session對(duì)象。

7.添加新對(duì)象(簡(jiǎn)略)

ed_user = User(name='ed', fullname='Ed Jones', password='edspassword')
session.add(ed_user)

至此,我們可以認(rèn)為,新添加的這個(gè)對(duì)象實(shí)例仍在等待中;ed_user對(duì)象現(xiàn)在并不代表數(shù)據(jù)庫(kù)中的一行數(shù)據(jù)。直到使用flush進(jìn)程,Session才會(huì)讓SQL保持連接。如果查詢這條數(shù)據(jù)的話,所有等待信息會(huì)被第一時(shí)間刷新,查詢結(jié)果也會(huì)立即發(fā)行。

session.commit()

通過(guò)commit()可以提交所有剩余的更改到數(shù)據(jù)庫(kù)。

8.回滾

session.rollback()

9.查詢

通過(guò)Session的query()方法創(chuàng)建一個(gè)查詢對(duì)象。這個(gè)函數(shù)的參數(shù)數(shù)量是可變的,參數(shù)可以是任何類或者是類的描述的集合。下面是一個(gè)迭代輸出User類的例子:

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

Query也支持ORM描述作為參數(shù)。任何時(shí)候,多個(gè)類的實(shí)體或者是基于列的實(shí)體表達(dá)都可以作為query()函數(shù)的參數(shù),返回類型是元組:

name, fullname session.query(User.name,User.fullname): 

name, fullname

Query返回的元組被命名為KeyedTuple類的實(shí)例元組。并且可以把它當(dāng)成一個(gè)普通的Python數(shù)據(jù)類操作。元組的名字就相當(dāng)于屬性的屬性名,類的類名一樣。

 row session.query(User, User.name).all():

row.User,row.name
<User(name='ed',fullname='Ed Jones', password='f8s7ccs')>ed

label()不知道怎么解釋,看下例子就明白了。相當(dāng)于row.name

row session.query(User.name.label('name_label')).all():

(row.name_label)

aliased()我的理解是類的別名,如果有多個(gè)實(shí)體都要查詢一個(gè)類,可以用aliased()

from sqlalchemy.orm import aliased
user_alias = aliased(User, name='user_alias')
row  session.query(user_alias,user_alias.name).all():

row.user_alias

Query的 基本操作包括LIMIT和OFFSET,使用Python數(shù)組切片和ORDERBY結(jié)合可以讓操作變得很方便。

u session.query(User).order_by(User.id)[1:3]:

#只查詢第二條和第三條數(shù)據(jù)

9.1使用關(guān)鍵字變量過(guò)濾查詢結(jié)果,filter 和 filter_by都適用!2】使用很簡(jiǎn)單,下面列出幾個(gè)常用的操作:

query.filter(User.name == 'ed') #equals
query.filter(User.name != 'ed') #not equals
query.filter(User.name.like('%ed%')) #LIKE
uery.filter(User.name.in_(['ed','wendy', 'jack'])) #IN
query.filter(User.name.in_(session.query(User.name).filter(User.name.like('%ed%'))#IN
query.filter(~User.name.in_(['ed','wendy', 'jack']))#not IN
query.filter(User.name == None)#is None
query.filter(User.name != None)#not None
from sqlalchemy import and_
query.filter(and_(User.name =='ed',User.fullname =='Ed Jones')) # and
query.filter(User.name == 'ed',User.fullname =='Ed Jones') # and
query.filter(User.name == 'ed').filter(User.fullname == 'Ed Jones')# and
from sqlalchemy import or_
query.filter(or_(User.name =='ed', User.name =='wendy')) #or
query.filter(User.name.match('wendy')) #match

9.2.返回列表和數(shù)量(標(biāo)量?)

all()返回一個(gè)列表:可以進(jìn)行Python列表的操作。

query = session.query(User).filter(User.name.like('%ed')).order_by(User.id)
query.all()
[<User(name='ed',fullname='EdJones', password='f8s7ccs')>,<User(name='fred', fullname='FredFlinstone', password='blah')>]

first()適用于限制一個(gè)情況,返回查詢到的第一個(gè)結(jié)果作為標(biāo)量?:好像只能作為屬性,類

query.first()

<User(name='ed',fullname='Ed Jones', password='f8s7ccs')>

one()完全獲取所有行,并且如果查詢到的不只有一個(gè)對(duì)象或是有復(fù)合行,就會(huì)拋出異常。

from sqlalchemy.orm.exc import MultipleResultsFound
user = query.one()
:

  user = query.one()
except   MultipleResultsFound, e:
  print e
Multiple rows were found for one()

如果一行也沒(méi)有:

from sqlalchemy.orm.exc import NoResultFound
:

  user = query.filter(User.id == 99).one()
except NoResultFound, e:
  print e
No row was found for one()

one()方法對(duì)于想要解決“no items found”和“multiple items found”是不同的系統(tǒng)是極好的。(這句有語(yǔ)病。├鐆eb服務(wù)返回,本來(lái)是在no results found情況下返回”404“的,結(jié)果在多個(gè)results found情況下也會(huì)跑出一個(gè)應(yīng)用異常。

scalar()作為one()方法的依據(jù),并且在one()成功基礎(chǔ)上返回行的第一列。

query = session.query(User.id).filter(User.name == 'ed')
query.scalar()

7

9.3.使用字符串SQL

字符串能使Query更加靈活,通過(guò)text()構(gòu)造指定字符串的使用,這種方法可以用在很多方法中,像filter()和order_by()。

from sqlalchemy import text
for user in session.query(User).filter(text("id<224")).order_by(text("id")).all()

綁定參數(shù)可以指定字符串,用params()方法指定數(shù)值。

session.query(User).filter(text("id<:value and name=:name")).\

params(value=224, name='fred').order_by(User.id).one()
 

如果要用一個(gè)完整的SQL語(yǔ)句,可以使用from_statement()。

ession.query(User).from_statement(text("SELECT* FROM users where name=:name")).\
 params(name='ed').all()

也可以用from_statement()獲取完整的”raw”,用字符名確定希望被查詢的特定列:

session.query("id","name", "thenumber12").\

from_statement(text("SELECT id, name, 12 as ""thenumber12 FROM users where name=:name")).\

 params(name='ed').all()

[(1,u'ed', 12)]
感覺(jué)這個(gè)不太符合ORM的思想啊。。。

9.4 計(jì)數(shù)

count()用來(lái)統(tǒng)計(jì)查詢結(jié)果的數(shù)量。

session.query(User).filter(User.name.like('%ed')).count()

func.count()方法比count()更高級(jí)一點(diǎn)【3】

from sqlalchemy import func
 session.query(func.count(User.name),User.name).group_by(User.name).all()
[(1,u'ed'), (1,u'fred'), (1,u'mary'), (1,u'wendy')]

為了實(shí)現(xiàn)簡(jiǎn)單計(jì)數(shù)SELECT count(*) FROM table,可以這么寫(xiě):

session.query(func.count('*')).select_from(User).scalar()

如果我們明確表達(dá)計(jì)數(shù)是根據(jù)User表的主鍵的話,可以省略select_from(User):

session.query(func.count(User.id)).scalar()

上面兩行結(jié)果均為4。

10.建立聯(lián)系(外鍵)

是時(shí)候考慮怎樣映射和查詢一個(gè)和Users表關(guān)聯(lián)的第二張表了。假設(shè)我們系統(tǒng)的用戶可以存儲(chǔ)任意數(shù)量的email地址。我們需要定義一個(gè)新表Address與User相關(guān)聯(lián)。

ForeignKey

relationship, backref
class Address(Base):
__tablename__ = 'addresses'
id= Column(Integer, primary_key=True)
email_address = Column(String, nullable=False)
user_id = Column(Integer, ForeignKey('users.id'))
user = relationship("User", backref=backref('addresses',order_by=id))
def__repr__(self):
 return"<Address(email_address='%s')>"%self.email_address

構(gòu)造類和外鍵簡(jiǎn)單,就不過(guò)多贅述。主要說(shuō)明以下relationship()函數(shù):這個(gè)函數(shù)告訴ORM,Address類應(yīng)該和User類連接起來(lái),通過(guò)使用addresses.user。relationship()使用外鍵明確這兩張表的關(guān)系。決定Adderess.user屬性是多對(duì)一的。relationship()的子函數(shù)backref()提供表達(dá)反向關(guān)系的細(xì)節(jié):relationship()對(duì)象的集合被User.address引用。多對(duì)一的反向關(guān)系總是一對(duì)多。更多的細(xì)節(jié)參考Basic RelRational Patterns。

這兩個(gè)互補(bǔ)關(guān)系:Address.user和User.addresses被稱為雙向關(guān)系。這是SQLAlchemy ORM的一個(gè)非常關(guān)鍵的功能。更多關(guān)系backref的細(xì)節(jié)參見(jiàn)Linking Relationships with Backref。

假設(shè)聲明的方法已經(jīng)開(kāi)始使用,relationship()中和其他類關(guān)聯(lián)的參數(shù)可以通過(guò)strings指定。在上文的User類中,一旦所有映射成功,為了產(chǎn)生實(shí)際的參數(shù),這些字符串會(huì)被當(dāng)做Python的表達(dá)式。下面是一個(gè)在User類中創(chuàng)建雙向聯(lián)系的例子:

class User(Base):
addresses = relationship("Address", order_by="Address.id", backref="user")

一些知識(shí):

在大多數(shù)的外鍵約束(盡管不是所有的)關(guān)系數(shù)據(jù)庫(kù)只能鏈接到一個(gè)主鍵列,或具有唯一約束的列。

外鍵約束如果是指向多個(gè)列的主鍵,并且它本身也具有多列,這種被稱為“復(fù)合外鍵”。

外鍵列可以自動(dòng)更新自己來(lái)相應(yīng)它所引用的行或者列。這被稱為級(jí)聯(lián),是一種建立在關(guān)系數(shù)據(jù)庫(kù)的功能。

外鍵可以參考自己的表格。這種被稱為“自引”外鍵。

我們需要在數(shù)據(jù)庫(kù)中創(chuàng)建一個(gè)addresses表,所以我們會(huì)創(chuàng)建另一個(gè)元數(shù)據(jù),這將會(huì)跳過(guò)已經(jīng)創(chuàng)建的表。

11.操作主外鍵關(guān)聯(lián)的對(duì)象

現(xiàn)在我們已經(jīng)在User類中創(chuàng)建了一個(gè)空的addresser集合,可變集合類型,例如set和dict,都可以用,但是默認(rèn)的集合類型是list。

jack = User(name='jack', fullname='Jack Bean', password='gjffdd')
jack.addresses
[]

現(xiàn)在可以直接在User對(duì)象中添加Address對(duì)象。只需要指定一個(gè)完整的列表:

jack.addresses = [Address(email_address='jack@google.com'),Address(email_address='j25@yahoo.com')]
當(dāng)使用雙向關(guān)系時(shí),元素在一個(gè)類中被添加后便會(huì)自動(dòng)在另一個(gè)類中添加。這種行為發(fā)生在Python的更改事件屬性中而不是用SQL語(yǔ)句:
>>> jack.addresses[1]
<Address(email_address='j25@yahoo.com')>
>>> jack.addresses[1].user
<User(name='jack', fullname='Jack Bean', password='gjffdd')>
把jack提交到數(shù)據(jù)庫(kù)中,再次查詢Jack,(No SQL is yet issued for Jack’s addresses:)這句實(shí)在是翻譯不了了,看看代碼就明白是什么意思:
>>> jack = session.query(User).\
...
filter_by(name='jack').one()
>>> jack
<User(name='jack',fullname='Jack Bean', password='gjffdd')>

>>>jack.addresses
[<Address(email_address='jack@google.com')>, <Address(email_address='j25@yahoo.com')>]
當(dāng)我們?cè)L問(wèn)uaddresses集合時(shí),SQL會(huì)被突然執(zhí)行,這是一個(gè)延遲加載(lazy loading)關(guān)系的典型例子,F(xiàn)在addresses集合加載完成并且可以像對(duì)待普通列表一樣對(duì)其進(jìn)行操作。以后我們會(huì)優(yōu)化這種加載方式。
12.使用JOINS查詢
現(xiàn)在我們有了兩張表,可以進(jìn)行更多的查詢操作,特別是怎樣對(duì)兩張表同時(shí)進(jìn)行查詢,Wikipediapage on SQL JOIN提供了很詳細(xì)的說(shuō)明,其中一些我們將在這里說(shuō)明。之前用Query.filter()時(shí),我們已經(jīng)用過(guò)JOIN了,filter是一種簡(jiǎn)單的隱式j(luò)oin:
>>>for u, a in session.query(User, Address).filter(User.id==Address.user_id).filter(Address.email_address=='jack@google.com').all():
    print u
    print a
<User(name='jack',fullname='JackBean', password='gjffdd')>
<Address(email_address='jack@google.com')>
用Query.join()方法會(huì)更加簡(jiǎn)單:
>>>session.query(User).join(Address).\
...     filter(Address.email_address=='jack@google.com').\
...     all()
[<User(name='jack',fullname='JackBean', password='gjffdd')>]
之所以Query.join()知道怎么join兩張表是因?yàn)樗鼈冎g只有一個(gè)外鍵。如果兩張表中沒(méi)有外鍵或者有一個(gè)以上的外鍵,當(dāng)下列幾種形式使用的時(shí)候,Query.join()可以表現(xiàn)的更好:
query.join(Address,User.id==Address.user_id)# 明確的條件
query.join(User.addresses)# 指定從左到右的關(guān)系
query.join(Address,User.addresses)    #同樣,有明確的目標(biāo)
query.join('addresses') # 同樣,使用字符串
 outerjoin()和join()用法相同
query.outerjoin(User.addresses)# LEFT OUTER JOIN
12.1使用別名
當(dāng)在多個(gè)表中查詢時(shí),如果同一張表需要被引用好幾次,SQL通常要求對(duì)這個(gè)表起一個(gè)別名,因此,SQL可以區(qū)分對(duì)這個(gè)表進(jìn)行的其他操作。Query也支持別名的操作。下面我們joinAddress實(shí)體兩次,找到同時(shí)擁有兩個(gè)不同email的用戶:
>>>from sqlalchemy.ormimport aliased
>>>adalias1 = aliased(Address)
>>>adalias2 = aliased(Address)
>>>for username, email1, email2 in\
...     session.query(User.name,adalias1.email_address,adalias2.email_address).\
...     join(adalias1, User.addresses).\
...     join(adalias2, User.addresses).\
...     filter(adalias1.email_address=='jack@google.com').\
...     filter(adalias2.email_address=='j25@yahoo.com'):
...     print username, email1, email2
jack jack@google.com j25@yahoo.com
12.1使用子查詢(暫時(shí)理解不了啊,多看代碼研究吧:()
from sqlalchemy.sqlimport func
stmt = session.query(Address.user_id,func.count('*').\
...         label('address_count')).\
...         group_by(Address.user_id).subquery()
>>> for u, count in session.query(User,stmt.c.address_count).\
...     outerjoin(stmt, User.id==stmt.c.user_id).order_by(User.id):
    print u, count
<User(name='ed',fullname='EdJones', password='f8s7ccs')> None
<User(name='wendy',fullname='Wendy Williams', password='foobar')> None
<User(name='mary',fullname='Mary Contrary', password='xxg527')> None
<User(name='fred',fullname='Fred Flinstone', password='blah')> None
<User(name='jack',fullname='Jack Bean', password='gjffdd')> 2
12.2從子查詢中選擇實(shí)體?
上面的代碼中我們只返回了包含子查詢的一個(gè)列的結(jié)果。如果想要子查詢映射到一個(gè)實(shí)體的話,使用aliased()設(shè)置一個(gè)要映射類的子查詢別名:
>>> stmt = session.query(Address).\
...      filter(Address.email_address!= 'j25@yahoo.com').\
...      subquery()
>>> adalias = aliased(Address, stmt) #?為什么有兩個(gè)參數(shù)?
>>> for user, address in session.query(User, adalias).\
...         join(adalias, User.addresses):
...     print user
...     print address
<User(name='jack',fullname='Jack Bean', password='gjffdd')>
<Address(email_address='jack@google.com')>

12.3使用EXISTS(存在?)

如果表達(dá)式返回任何行,EXISTS為真,這是一個(gè)布爾值。它可以用在jions中,也可以用來(lái)定位在一個(gè)關(guān)系表中沒(méi)有相應(yīng)行的情況:

>>>from sqlalchemy.sqlimport exists
>>> stmt = exists().where(Address.user_id==User.id)
>>>name, session.query(User.name).filter(stmt):
    print name
jack

等價(jià)于:

>>>for name, in session.query(User.name).\
...    filter(User.addresses.any()):
...     print name
jack

any()限制行匹配:

>>>for name, in session.query(User.name).\
...     filter(User.addresses.any(Address.email_address.like('%google%'))):
...     print name
jack

has()和any()一樣在應(yīng)對(duì)多對(duì)一關(guān)系的情況下(注意“~“意味著”NOT”)

>>> session.query(Address).\
...         filter(~Address.user.has(User.name=='jack')).all()
[]

12.4 常見(jiàn)的關(guān)系運(yùn)算符

== != None 都是用在多對(duì)一中,而contains()用在一對(duì)多的集合中:

query.filter(Address.user == someuser)
query.filter(User.addresses.contains(someaddress))

Any()(用于集合中):

query.filter(User.addresses.any(Address.email_address == 'bar'))#also takes keyword arguments:
query.filter(User.addresses.any(email_address='bar'))

as()(用在標(biāo)量?不在集合中):

query.filter(Address.user.has(name='ed'))

Query.with_parent()(所有關(guān)系都適用):

session.query(Address).with_parent(someuser,'addresses')

13 預(yù)先加載(跟性能有關(guān))和lazy loading相對(duì),建議直接查看文檔吧


    相關(guān)評(píng)論

    閱讀本文后您有什么感想? 已有人給出評(píng)價(jià)!

    • 8 喜歡喜歡
    • 3 頂
    • 1 難過(guò)難過(guò)
    • 5 囧
    • 3 圍觀圍觀
    • 2 無(wú)聊無(wú)聊

    熱門(mén)評(píng)論

    最新評(píng)論

    發(fā)表評(píng)論 查看所有評(píng)論(0)

    昵稱:
    表情: 高興 可 汗 我不要 害羞 好 下下下 送花 屎 親親
    字?jǐn)?shù): 0/500 (您的評(píng)論需要經(jīng)過(guò)審核才能顯示)