新聞中心
隨著視頻技術(shù)的迅速發(fā)展以及移動(dòng)互聯(lián)網(wǎng)的不斷普及,越來(lái)越多的人開(kāi)始使用手機(jī)、平板等移動(dòng)設(shè)備觀看視頻,而這樣的設(shè)備又往往由于存儲(chǔ)空間有限,需要一種輕量級(jí)的存儲(chǔ)方式。在這類(lèi)需求下,SQLite數(shù)據(jù)庫(kù)成為了存儲(chǔ)視頻的首選。

創(chuàng)新互聯(lián)專(zhuān)注于企業(yè)全網(wǎng)整合營(yíng)銷(xiāo)推廣、網(wǎng)站重做改版、朝天網(wǎng)站定制設(shè)計(jì)、自適應(yīng)品牌網(wǎng)站建設(shè)、html5、電子商務(wù)商城網(wǎng)站建設(shè)、集團(tuán)公司官網(wǎng)建設(shè)、外貿(mào)網(wǎng)站建設(shè)、高端網(wǎng)站制作、響應(yīng)式網(wǎng)頁(yè)設(shè)計(jì)等建站業(yè)務(wù),價(jià)格優(yōu)惠性價(jià)比高,為朝天等各大城市提供網(wǎng)站開(kāi)發(fā)制作服務(wù)。
1. SQLite數(shù)據(jù)庫(kù)的簡(jiǎn)介
在介紹SQLite數(shù)據(jù)庫(kù)在存儲(chǔ)視頻中的應(yīng)用之前,我們需要先了解一下SQLite數(shù)據(jù)庫(kù)的基本概念。SQLite是一種輕量級(jí)的關(guān)系型數(shù)據(jù)庫(kù),其數(shù)據(jù)庫(kù)引擎實(shí)現(xiàn)在一個(gè)相對(duì)小的C庫(kù)中,不需要與獨(dú)立的服務(wù)器進(jìn)行交互,可直接嵌入到應(yīng)用程序中使用。因此,SQLite具有占用空間小、性能高、易于維護(hù)等諸多優(yōu)點(diǎn),特別適用于嵌入式系統(tǒng)或移動(dòng)設(shè)備等有限空間的環(huán)境下。
2. SQLite數(shù)據(jù)庫(kù)在存儲(chǔ)視頻中的應(yīng)用
在移動(dòng)設(shè)備中,存儲(chǔ)空間通常比較有限,而且視頻文件體積較大,因此傳統(tǒng)的視頻存儲(chǔ)方式(如本地存儲(chǔ)、儲(chǔ)存在云端)不僅占用存儲(chǔ)空間,同時(shí)還會(huì)影響用戶觀看視頻的體驗(yàn)。相比之下,SQLlite數(shù)據(jù)庫(kù)具有較小的占用空間,可以在存儲(chǔ)大量視頻的同時(shí),減少占用存儲(chǔ)空間的負(fù)擔(dān),提高存儲(chǔ)效率。
另外,SQLite數(shù)據(jù)庫(kù)支持多種數(shù)據(jù)類(lèi)型(如BLOB、TEXT、INTEGER等),可實(shí)現(xiàn)對(duì)視頻、圖片、音頻等多種格式的存儲(chǔ)和操作。同時(shí),SQLite也支持事務(wù)處理和數(shù)據(jù)備份等功能,保證數(shù)據(jù)的安全性和完整性,給用戶提供更好的保障。
3. SQLite數(shù)據(jù)庫(kù)在視頻應(yīng)用中的實(shí)踐
實(shí)踐證明,SQLite數(shù)據(jù)庫(kù)已經(jīng)被廣泛應(yīng)用于視頻應(yīng)用中。例如,在一些流媒體應(yīng)用中,采用SQLite數(shù)據(jù)庫(kù)存儲(chǔ)視頻信息和用戶數(shù)據(jù),便于實(shí)現(xiàn)多平臺(tái)共享,同時(shí)可減少服務(wù)器成本和網(wǎng)絡(luò)流量。又如,一些觀看視頻的應(yīng)用,在使用SQLite數(shù)據(jù)庫(kù)儲(chǔ)存視頻時(shí),結(jié)合緩存、網(wǎng)絡(luò)傳輸技術(shù)等技術(shù)手段,提高了用戶觀看視頻的體驗(yàn),降低了卡頓等問(wèn)題。
SQLite數(shù)據(jù)庫(kù)是一種輕量級(jí)的存儲(chǔ)視頻的首選。在實(shí)際的應(yīng)用中,SQLite數(shù)據(jù)庫(kù)不僅能夠提高存儲(chǔ)效率,保證數(shù)據(jù)完整性,還能夠?qū)崿F(xiàn)多種格式的存儲(chǔ)和操作。對(duì)于移動(dòng)設(shè)備和服務(wù)器開(kāi)發(fā)人員,選擇SQLite數(shù)據(jù)庫(kù)作為視頻存儲(chǔ)方式,是一種明智而可行的選擇。
成都網(wǎng)站建設(shè)公司-創(chuàng)新互聯(lián)為您提供網(wǎng)站建設(shè)、網(wǎng)站制作、網(wǎng)頁(yè)設(shè)計(jì)及定制高端網(wǎng)站建設(shè)服務(wù)!
后端編程Python3-數(shù)據(jù)庫(kù)編程
對(duì)大多數(shù)軟件開(kāi)發(fā)者而言,術(shù)語(yǔ)數(shù)據(jù)庫(kù)通常是指RDBMS(關(guān)系數(shù)據(jù)庫(kù)管理系統(tǒng)), 這些系統(tǒng)使用表格(類(lèi)似于電子表格的網(wǎng)格),其中行表示記錄,列表示記錄的字段。表格及其中存放的數(shù)據(jù)是使用SQL (結(jié)構(gòu)化査詢語(yǔ)言)編寫(xiě)的語(yǔ)句來(lái)創(chuàng)建并操縱的。Python提供了用于操縱SQL數(shù)據(jù)庫(kù)的API(應(yīng)用程序接口),通常與作為標(biāo)準(zhǔn)的SQLite 3數(shù)據(jù)庫(kù)一起發(fā)布。
另一種數(shù)據(jù)庫(kù)是DBM (數(shù)據(jù)庫(kù)管理器),其中存放任意數(shù)量的鍵-值項(xiàng)。Python 的標(biāo)準(zhǔn)庫(kù)提供了幾種DBM的接口,包括某些特定于UNIX平臺(tái)的。DBM的工作方式 與Python中的字典類(lèi)似,區(qū)別在于DBM通常存放于磁盤(pán)上而不是內(nèi)存中,并且其鍵與值總是bytes對(duì)象,并可能受到長(zhǎng)度限制。本章之一節(jié)中講解的shelve模塊提供了方便的DBM接口,允許我們使用字符串作為鍵,使用任意(picklable)對(duì)象作為值。
如果可用的 DBM 與 SQLite 數(shù)據(jù)庫(kù)不夠充分,Python Package Index, pypi.python.org/pypi中提供了大量數(shù)據(jù)庫(kù)相關(guān)的包,包括bsddb DBM (“Berkeley DB”),對(duì)象-關(guān)系映射器,比如SQLAlchemy (www.sqlalchemy.org),以及流行的客戶端/服務(wù)器數(shù)據(jù)的接口,比如 DB2、Informix、Ingres、MySQL、ODBC 以及 PostgreSQL。
本章中,我們將實(shí)現(xiàn)某程序的兩個(gè)版本,該程序用于維護(hù)一個(gè)DVD列表,并追蹤每個(gè)DVD的標(biāo)題、發(fā)行年份、時(shí)間長(zhǎng)度以及發(fā)行者。該程序的之一版使用DBM (通過(guò)shelve模塊)存放其數(shù)據(jù),第二版則使用SQLite數(shù)據(jù)庫(kù)。兩個(gè)程序都可以加載與保存簡(jiǎn)單的XML格式,這使得從某個(gè)程序?qū)С鯠VD數(shù)據(jù)并將其導(dǎo)入到其他程序成為可能。與DBM版相比,基于SQL的程序提供了更多一些的功能,并且其數(shù)據(jù)設(shè)計(jì)也稍干凈一些。
12.1 DBM數(shù)據(jù)庫(kù)
shelve模塊為DBM提供了一個(gè)wrapper,借助于此,我們?cè)谂cDBM交互時(shí),可以將其看做一個(gè)字典,這里是假定我們只使用字符串鍵與picklable值,實(shí)際處理時(shí), shelve模塊會(huì)將鍵與值轉(zhuǎn)換為bytes對(duì)象(或者反過(guò)來(lái))。
由于shelve模塊使用的是底層的DBM,因此,如果其他計(jì)算機(jī)上沒(méi)有同樣的DBM,那么在某臺(tái)計(jì)算機(jī)上保存的DBM文件在其他機(jī)器上無(wú)法讀取是可能的。為解決這一問(wèn)題,常見(jiàn)的解決方案是對(duì)那些必須在機(jī)器之間可傳輸?shù)奈募峁ML導(dǎo)入與導(dǎo)出功能,這也是我們?cè)诒竟?jié)的DVD程序dvds-dbm.py中所做的。
對(duì)鍵,我們使用DVD的標(biāo)題;對(duì)值,則使用元組,其中存放發(fā)行者、發(fā)行年份以及時(shí)間。借助于shelve模塊,我們不需要進(jìn)行任何數(shù)據(jù)轉(zhuǎn)換,并可以把DBM對(duì)象當(dāng)做一個(gè)字典進(jìn)行處理。
程序在結(jié)構(gòu)上類(lèi)似于我們前面看到的那種菜單驅(qū)動(dòng)型的程序,因此,這里主要展示的是與DBM程序設(shè)計(jì)相關(guān)的那部分。下面給出的是程序main()函數(shù)中的一部分, 忽略了其中菜單處理的部分代碼。
db = None
try:
db = shelve.open(filename, protocol=pickle.HIGHEST_PROTOCOL)
finally:
if db is not None:
db.dose()
這里我們已打開(kāi)(如果不存在就創(chuàng)建)指定的DBM文件,以便于對(duì)其進(jìn)行讀寫(xiě)操作。每一項(xiàng)的值使用指定的pickle協(xié)議保存為一個(gè)pickle,現(xiàn)有的項(xiàng)可以被讀取, 即便是使用更底層的協(xié)議保存的,因?yàn)镻ython可以計(jì)算出用于讀取pickle的正確協(xié)議。最后,DBM被關(guān)閉——其作用是清除DBM的內(nèi)部緩存,并確保磁盤(pán)文件可以反映出已作的任何改變,此外,文件也需要關(guān)閉。
該程序提供了用于添加、編輯、列出、移除、導(dǎo)入、導(dǎo)出DVD數(shù)據(jù)的相應(yīng)選項(xiàng)。除添加外,我們將忽略大部分用戶接口代碼,同樣是因?yàn)橐呀?jīng)在其他上下文中進(jìn)行了展示。
def add_dvd(db):
title = Console.get_string(“Title”, “title”)
if not title:
return
director = Console.get_string(“Director”, “director”)
if not director:
return
year = Console.get_integer(“Year”, “year”,minimum=1896,
maximum=datetime,date.today().year)
duration = Console.get_integer(“Duration (minutes)”, “minutes“, minimum=0, maximum=60*48)
db = (director, year, duration)
db.sync()
像程序菜單調(diào)用的所有函數(shù)一樣,這一函數(shù)也以DBM對(duì)象(db)作為其唯一參數(shù)。該函數(shù)的大部分工作都是獲取DVD的詳細(xì)資料,在倒數(shù)第二行,我們將鍵-值項(xiàng)存儲(chǔ)在DBM文件中,DVD的標(biāo)題作為鍵,發(fā)行者、年份以及時(shí)間(由shelve模塊pickled在一起)作為值。
為與Python通常的一致性同步,DBM提供了與字典一樣的API,因此,除了 shelve.open() 函數(shù)(前面已展示)與shelve.Shelf.sync()方法(該方法用于清除shelve的內(nèi)部緩存,并對(duì)磁盤(pán)上文件的數(shù)據(jù)與所做的改變進(jìn)行同步——這里就是添加一個(gè)新項(xiàng)),我們不需要學(xué)習(xí)任何新語(yǔ)法。
def edit_dvd(db):
old_title = find_dvd(db, “edit”)
if old_title is None:
return
title = Console.get.string(“Title”, “title”, old_title)
if not title:
return
director, year, duration = db
…
db= (director, year, duration)
if title != old_title:
del db
db.sync()
為對(duì)某個(gè)DVD進(jìn)行編輯,用戶必須首先選擇要操作的DVD,也就是獲取DVD 的標(biāo)題,因?yàn)闃?biāo)題用作鍵,值則用于存放其他相關(guān)數(shù)據(jù)。由于必要的功能在其他場(chǎng)合 (比如移除DVD)也需要使用,因此我們將其實(shí)現(xiàn)在一個(gè)單獨(dú)的find_dvd()函數(shù)中,稍后將査看該函數(shù)。如果找到了該DVD,我們就獲取用戶所做的改變,并使用現(xiàn)有值作為默認(rèn)值,以便提高交互的速度。(對(duì)于這一函數(shù),我們忽略了大部分用戶接口代碼, 因?yàn)槠渑c添加DVD時(shí)幾乎是相同的。)最后,我們保存數(shù)據(jù),就像添加時(shí)所做的一樣。如果標(biāo)題未作改變,就重寫(xiě)相關(guān)聯(lián)的值;如果標(biāo)題已改變,就創(chuàng)建一個(gè)新的鍵-值對(duì), 并且需要?jiǎng)h除原始項(xiàng)。
def find_dvd(db, message):
message = “(Start of) title to ” + message
while True:
matches =
start = Console.get_string(message, “title”)
if not start:
return None
for title in db:
if title.lower().startswith(start.lower()):
matches.append(title)
if len(matches) == 0:
print(“There are no dvds starting with”, start)
continue
elif len(matches) == 1:
return matches
elif len(matches) > DISPLAY_LIMIT:
print(“Too many dvds start with {0}; try entering more of the title”.format(start)
continue
else:
matches = sorted(matches, key=str.lower)
for i, match in enumerate(matches):
print(“{0}: {1}”.format(i+1, match))
which = Console.get_integer(“Number (or 0 to cancel)”,
“number”, minimum=1, maximum=len(matches))
return matches if which != 0 else None
為盡可能快而容易地發(fā)現(xiàn)某個(gè)DVD,我們需要用戶只輸入其標(biāo)題的一個(gè)或頭幾個(gè)字符。在具備了標(biāo)題的起始字符后,我們?cè)贒BM中迭代并創(chuàng)建一個(gè)匹配列表。如果只有一個(gè)匹配項(xiàng),就返回該項(xiàng);如果有幾個(gè)匹配項(xiàng)(但少于DISPLAY_LIMIT, 一個(gè)在程序中其他地方設(shè)置的整數(shù)),就以大小寫(xiě)不敏感的順序展示所有這些匹配項(xiàng),并為每一項(xiàng)設(shè)置一個(gè)編號(hào),以便用戶可以只輸入編號(hào)就可以選擇某個(gè)標(biāo)題。(Console.get_integer()函數(shù)可以接受0,即便最小值大于0,以便0可以用作一個(gè)刪除值。通過(guò)使用參數(shù)allow_zero=False, 可以禁止這種行為。我們不能使用Enter鍵,也就是說(shuō),沒(méi)有什么意味著取消,因?yàn)槭裁匆膊惠斎胍馕吨邮苣J(rèn)值。)
def list_dvds(db):
start =””
if len(db)> DISPLAY.LIMIT:
start = Console.get_string(“List those starting with ”, “start”)
print()
for title in sorted(db, key=str.lower):
if not start or title.Iower().startswith(start.lower()):
director, year, duration = db
print(“{title} ({year}) {duration} minute{0}, by ”
“{director}”.format(Util.s(duration),**locals()))
列出所有DVD (或者那些標(biāo)題以某個(gè)子字符串引導(dǎo))就是對(duì)DBM的所有項(xiàng)進(jìn)行迭代。
Util.s()函數(shù)就是簡(jiǎn)單的s = lambda x: “” if x == 1 else “s”,因此,如果時(shí)間長(zhǎng)度不是1分鐘,就返回”s”。
def remove_dvd(db):
title = find_dvd(db, “remove”)
if title is None:
return
ans = Console.get_bool(“Remove {0}?”.format(title), “no”)
if ans:
del db
db.sync()
要移除一個(gè)DVD,首先需要找到用戶要移除的DVD,并請(qǐng)求確認(rèn),獲取后從DBM中刪除該項(xiàng)即可。
到這里,我們展示了如何使用shelve模塊打開(kāi)(或創(chuàng)建)一個(gè)DBM文件,以及如何向其中添加項(xiàng)、編輯項(xiàng)、對(duì)其項(xiàng)進(jìn)行迭代以及移除某個(gè)項(xiàng)。
遺憾的是,在我們的數(shù)據(jù)設(shè)計(jì)中存在一個(gè)瑕疵。發(fā)行者名稱(chēng)是重復(fù)的,這很容易導(dǎo)致不一致性,比如,發(fā)行者Danny DeVito可能被輸入為”Danny De Vito”,用于 一個(gè)電影;也可以輸入為“Danny deVito”,用于另一個(gè)。為解決這一問(wèn)題,可以使用兩個(gè)DBM文件,主DVD文件使用標(biāo)題鍵與(年份,時(shí)間長(zhǎng)度,發(fā)行者ID)值; 發(fā)行者文件使用發(fā)行者ID (整數(shù))鍵與發(fā)行者名稱(chēng)值。下一節(jié)展示的SQL數(shù)據(jù)庫(kù) 版程序?qū)⒈苊膺@一瑕疵,這是通過(guò)使用兩個(gè)表格實(shí)現(xiàn)的,一個(gè)用于DVD,另一個(gè)用于發(fā)行者。
12.2 SQL數(shù)據(jù)庫(kù)
大多數(shù)流行的SQL數(shù)據(jù)庫(kù)的接口在第三方模塊中是可用的,Python帶有sqlite3 模塊(以及SQLite 3數(shù)據(jù)庫(kù)),因此,在Python中,可以直接開(kāi)始數(shù)據(jù)庫(kù)程序設(shè)計(jì)。SQLite是一個(gè)輕量級(jí)的SQL數(shù)據(jù)庫(kù),缺少很多諸如PostgreSQL這種數(shù)據(jù)庫(kù)的功能, 但非常便于構(gòu)造原型系統(tǒng),并且在很多情況下也是夠用的。
為使后臺(tái)數(shù)據(jù)庫(kù)之間的切換盡可能容易,PEP 249 (Python Database API Specification v2.0)提供了稱(chēng)為DB-API 2.0的API規(guī)范。數(shù)據(jù)庫(kù)接口應(yīng)該遵循這一規(guī)范,比如sqlite3模塊就遵循這一規(guī)范,但不是所有第三方模塊都遵循。API規(guī)范中指定了兩種主要的對(duì)象,即連接對(duì)象與游標(biāo)對(duì)象。表12-1與表12-2中分別列出了這兩種對(duì)象必須支持的API。在sqlite3模塊中,除DB-API 2.0規(guī)范必需的之外,其連接對(duì)象與游標(biāo)對(duì)象都提供了很多附加的屬性與方法。
DVD程序的SQL版本為dvds.sql.py,該程序?qū)l(fā)行者與DVD數(shù)據(jù)分開(kāi)存儲(chǔ),以 避免重復(fù),并提供一個(gè)新菜單,以供用戶列出發(fā)行者。該程序使用的兩個(gè)表格在圖12-1
def connect(filename):
create= not os.path.exists(filename)
db = sqlite3.connect(filename)
if create:
cursor = db.cursor()
cursor.execute(“CREATE TABLE directors (”
“id INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE NOT NULL, ”
“name TEXT UNIQUE NOT NULL)”)
cursor.execute(“CREATE TABLE dvds (”
“id INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE NOT NULL, ”
“title TEXT NOT NULL, ”
“year INTEGER NOT NULL,”
“duration INTEGER NOT NULL, ”
“director_id INTEGER NOT NULL, ”
“FOREIGN KEY (director_id) REFERENCES directors)”)
db.commit()
return db
sqlite3.connect()函數(shù)會(huì)返回一個(gè)數(shù)據(jù)庫(kù)對(duì)象,并打開(kāi)其指定的數(shù)據(jù)庫(kù)文件。如果該文件不存在,就創(chuàng)建一個(gè)空的數(shù)據(jù)庫(kù)文件。鑒于此,在調(diào)用sqlite3.connect()之前,我們要注意數(shù)據(jù)庫(kù)是否是準(zhǔn)備從頭開(kāi)始創(chuàng)建,如果是,就必須創(chuàng)建該程序要使用的表格。所有査詢都是通過(guò)一個(gè)數(shù)據(jù)庫(kù)游標(biāo)完成的,可以從數(shù)據(jù)庫(kù)對(duì)象的cursor()方法獲取。
注意,兩個(gè)表格都是使用一個(gè)ID字段創(chuàng)建的,ID字段有一個(gè)AUTOINCREMENT 約束——這意味著SQLite會(huì)自動(dòng)為ID字段賦予唯一性的數(shù)值,因此,在插入新記錄時(shí),我們可以將這些字段留給SQLite處理。
SQLite支持有限的數(shù)據(jù)類(lèi)型——實(shí)際上就是布爾型、數(shù)值型與字符串——但使用數(shù)據(jù)’‘適配器”可以對(duì)其進(jìn)行擴(kuò)展,或者是擴(kuò)展到預(yù)定義的數(shù)據(jù)類(lèi)型(比如那些用于日期與datetimes的類(lèi)型),或者是用于表示任意數(shù)據(jù)類(lèi)型的自定義類(lèi)型。DVD程序并不需要這一功能,如果需要,sqlite3模塊的文檔提供了很多詳細(xì)解釋。我們使用的外部鍵語(yǔ)法可能與用于其他數(shù)據(jù)庫(kù)的語(yǔ)法不同,并且在任何情況下,只是記錄我們的意圖,因?yàn)镾QLite不像很多其他數(shù)據(jù)庫(kù)那樣需要強(qiáng)制關(guān)系完整性,sqlite3另一點(diǎn)與眾不同的地方在于其默認(rèn)行為是支持隱式的事務(wù)處理,因此,沒(méi)有提供顯式的“開(kāi)始事務(wù)” 方法。
def add_dvd(db):
title = Console.get_string(“Title”, “title”)
if not title:
return
director = Console.get_string(“Director”, “director”)
if not director:
return
year = Console.get_integer(“Year”, “year”, minimum=1896,
maximum=datetime.date.today().year)
duration = Console.get_integer(“Duration (minutes)”, “minutes”,
minimum=0,maximum=60*48)
director_id = get_and_set_director(db, director)
cursor = db.cursor()
cursor.execute(“INSERT INTO dvds ”
“(title, year, duration, director_id)”
“VALUES (?, ?, ?, ?)”,
(title, year, duration, director_id))
db.commit()
這一函數(shù)的開(kāi)始代碼與dvds-dbm.py程序中的對(duì)應(yīng)函數(shù)一樣,但在完成數(shù)據(jù)的收集后,與原來(lái)的函數(shù)有很大的差別。用戶輸入的發(fā)行者可能在也可能不在directors表格中,因此,我們有一個(gè)get_and_set_director()函數(shù),在數(shù)據(jù)庫(kù)中尚無(wú)某個(gè)發(fā)行者時(shí), 該函數(shù)就將其插入到其中,無(wú)論哪種情況都返回就緒的發(fā)行者ID,以便在需要的時(shí)候插入到dvds表。在所有數(shù)據(jù)都可用后,我們執(zhí)行一條SQL INSERT語(yǔ)句。我們不需要指定記錄ID,因?yàn)镾QLite會(huì)自動(dòng)為我們提供。
在査詢中,我們使用問(wèn)號(hào)(?)作為占位符,每個(gè)?都由包含SQL語(yǔ)句的字符串后面的序列中的值替代。命名的占位符也可以使用,后面在編輯記錄時(shí)我們將看到。盡管避免使用占位符(而只是簡(jiǎn)單地使用嵌入到其中的數(shù)據(jù)來(lái)格式化SQL字符串)也是可能的,我們建議總是使用占位符,并將數(shù)據(jù)項(xiàng)正確編碼與轉(zhuǎn)義的工作留給數(shù)據(jù)庫(kù)模塊來(lái)完成。使用占位符的另一個(gè)好處是可以提高安全性,因?yàn)檫@可以防止任意的SQL 被惡意地插入到一個(gè)査詢中。
def get_and_set_director(db, director):
director_id = get_director_id(db, director)
if directorjd is not None:
return director_id
cursor = db.cursor()
cursor.execute(“l(fā)NSERT INTO directors (name) VALUES (?)”,(director,))
db.commit()
return get_director_id(db, director)
這一函數(shù)返回給定發(fā)行者的ID,并在必要的時(shí)候插入新的發(fā)行者記錄。如果某個(gè)記錄入,我們首先嘗試使用get_director_id()函數(shù)取回其ID。
def get_director_id(db, director):
cursor = db.cursor()
cursor.execute(“SELECT id FROM directors WHERE name=?”,(director,))
fields = cursor.fetchone()
return fields if fields is not None else None
get_director_id()函數(shù)返回給定發(fā)行者的ID,如果數(shù)據(jù)庫(kù)中沒(méi)有指定的發(fā)行者,就返回None。我們使用fetchone()方法,因?yàn)榛蛘哂幸粋€(gè)匹配的記錄,或者沒(méi)有。(我們知道,不會(huì)有重復(fù)的發(fā)行者,因?yàn)閐irectors表格的名稱(chēng)字段有一個(gè)UNIQUE約束,在任何情況下,在添加一個(gè)新的發(fā)行者之前,我們總是先檢査其是否存在。)這種取回方法總是返回一個(gè)字段序列(如果沒(méi)有更多的記錄,就返回None)。即便如此,這里我們只是請(qǐng)求返回一個(gè)單獨(dú)的字段。
def edit_dvd(db):
title, identity = find_dvd(db, “edit”)
if title is None:
return
title = Console.get_string(“Title”,”title”, title)
if not title:
return
cursor = db.cursor()
cursor.execute(“SELECT dvds.year, dvds.duration, directors.name”
“FROM dvds, directors ”
“WHERE dvds.director_id = directors.id AND ”
“dvds.id=:id”, dict(id=identity))
year, duration, director = cursor.fetchone()
director = Console.get_string(“Director”, “director”, director)
if not director:
return
year = Console,get_integer(“Year”,”year”, year, 1896,datetime.date.today().year)
duration = Console.get_integer(“Duration (minutes)”, “minutes”,
duration, minimum=0, maximum=60*48)
director_id = get_and_set_director(db, director)
cursor.execute(“UPDATE dvds SET title=:title, year=:year,”
“duration=:duration, director_id=:directorjd ”
“WHERE id=:identity”, locals())
db.commit()
要編輯DVD記錄,我們必須首先找到用戶需要操縱的記錄。如果找到了某個(gè)記錄,我們就給用戶修改其標(biāo)題的機(jī)會(huì),之后取回該記錄的其他字段,以便將現(xiàn)有值作為默認(rèn)值,將用戶的輸入工作最小化,用戶只需要按Enter鍵就可以接受默認(rèn)值。這里,我們使用了命名的占位符(形式為:name),并且必須使用映射來(lái)提供相應(yīng)的值。對(duì)SELECT語(yǔ)句,我們使用一個(gè)新創(chuàng)建的字典;對(duì)UPDATE語(yǔ)句,我們使用的是由 locals()返回的字典。
我們可以同時(shí)為這兩個(gè)語(yǔ)句都使用新字典,這種情況下,對(duì)UPDATE語(yǔ)句,我們可以傳遞 dict(title=title, year=year, duration=duration, director_id=director_id, id=identity)),而非 locals()。
在具備所有字段并且用戶已經(jīng)輸入了需要做的改變之后,我們?nèi)』叵鄳?yīng)的發(fā)行者ID (如果必要就插入新的發(fā)行者記錄),之后使用新數(shù)據(jù)對(duì)數(shù)據(jù)庫(kù)進(jìn)行更新。我們采用了一種簡(jiǎn)化的方法,對(duì)記錄的所有字段進(jìn)行更新,而不僅僅是那些做了修改的字段。
在使用DBM文件時(shí),DVD標(biāo)題被用作鍵,因此,如果標(biāo)題進(jìn)行了修改,我們就需要?jiǎng)?chuàng)建一個(gè)新的鍵-值項(xiàng),并刪除原始項(xiàng)。不過(guò),這里每個(gè)DVD記錄都有一個(gè)唯一性的ID,該ID是記錄初次插入時(shí)創(chuàng)建的,因此,我們只需要改變?nèi)魏纹渌侄蔚闹担?而不需要其他操作。
def find_dvd(db, message):
message = “(Start of) title to ” + message
cursor = db.cursor()
while True: .
start = Console.get_stnng(message, “title”)
if not start:
return (None, None)
cursor.execute(“SELECT title, id FROM dvds ”
“WHERE title LIKE ? ORDER BY title”,
(start +”%”,))
records = cursor.fetchall()
if len(records) == 0:
print(“There are no dvds starting with”, start)
continue
elif len(records) == 1:
return records
elif len(records) > DISPLAY_LIMIT:
print(“Too many dvds ({0}) start with {1}; try entering ”
“more of the title”.format(len(records),start))
continue
else:
for i, record in enumerate(records):
print(“{0}:{1}”.format(i + 1, record))
which = Console.get_integer(“Number (or 0 to cancel)”,
“number”, minimum=1, maximum=len(records))
return records if which != 0 else (None, None)
這一函數(shù)的功能與dvdsdbm.py程序中的find_dvd()函數(shù)相同,并返回一個(gè)二元組 (DVD標(biāo)題,DVD ID)或(None, None),具體依賴(lài)于是否找到了某個(gè)記錄。這里并不需要在所有數(shù)據(jù)上進(jìn)行迭代,而是使用SQL通配符(%),因此只取回相關(guān)的記錄。
由于我們希望匹配的記錄數(shù)較小,因此我們一次性將其都取回到序列的序列中。如果有不止一個(gè)匹配的記錄,但數(shù)量上又少到可以顯示,我們就打印記錄,并將每條記錄附帶一個(gè)數(shù)字編號(hào),以便用戶可以選擇需要的記錄,其方式與在dvds-dbm.py程序中所做的類(lèi)似:
def list_dvds(db):
cursor = db.cursor()
sql = (“SELECT dvds.title, dvds.year, dvds.duration, ”
“directors.name FROM dvds, directors ”
“WHERE dvds.director_id = directors.id”)
start = None
if dvd_count(db) > DISPLAY_LIMIT:
start = Console.get_string(“List those starting with “, “start”)
sql += ” AND dvds.title LIKE ?”
sql += ” ORDER BY dvds.title”
print()
if start is None:
cursor.execute(sql)
else:
cursor.execute(sql, (start +”%”,))
for record in cursor:
print(“{0} ({0}) {0} minutes, by {0}”.format(record))
要列出每個(gè)DVD的詳細(xì)資料,我們執(zhí)行一個(gè)SELECT査詢。該査詢連接兩個(gè)表,如果記錄(由dvd_count()函數(shù)返回)數(shù)量超過(guò)了顯示限制值,就將第2個(gè)元素添加到WHERE 分支,之后執(zhí)行該査詢,并在結(jié)果上進(jìn)行迭代。每個(gè)記錄都是一個(gè)序列,其字段是與 SELECT査詢相匹配的。
def dvd_count(db):
cursor = db.cursor()
cursor.execute(“SELECT COUNT(*) FROM dvds”)
return cursor.fetchone()
我們將這幾行代碼放置在一個(gè)單獨(dú)的函數(shù)中,因?yàn)槲覀冊(cè)趲讉€(gè)不同的函數(shù)中都需要使用這幾行代碼。
我們忽略了 list_directors()函數(shù)的代碼,因?yàn)樵摵瘮?shù)在結(jié)構(gòu)上與list_dvds()函數(shù)非常類(lèi)似,只不過(guò)更簡(jiǎn)單一些,因?yàn)楸竞瘮?shù)只列出一個(gè)字段(name)。
def remove_dvd(db):
title, identity = find_dvd(db, “remove”)
if title is None:
return
ans = Console.get_bool(“Remove {0}?”.format(title), “no”)
if ans:
cursor = db.cursor()
cursor.execute(“DELETE FROM dvds WHERE id=?”, (identity,))
db.commit()
在用戶需要?jiǎng)h除一個(gè)記錄時(shí),將調(diào)用本函數(shù),并且本函數(shù)與dvds-dbm.py程序中 相應(yīng)的函數(shù)是非常類(lèi)似的。
到此,我們完全查閱了 dvds-sql.py程序,并且了解了如何創(chuàng)建數(shù)據(jù)庫(kù)表格、選取 記錄、在選定的記錄上進(jìn)行迭代以及插入、更新與刪除記錄。使用execute()方法,我們可以執(zhí)行底層數(shù)據(jù)庫(kù)所支持的任意SQL語(yǔ)句。
SQLite提供了比我們這里使用的多得多的功能,包括自動(dòng)提交模式(以及任意其他類(lèi)型的事務(wù)控制),以及創(chuàng)建可以在SQL查詢內(nèi)執(zhí)行的函數(shù)的能力。提供一個(gè)工廠函數(shù)并用于控制對(duì)每個(gè)取回的記錄返回什么(比如,一個(gè)字典或自定義類(lèi)型,而不是字段序列)也是可能的。此外,通過(guò)傳遞“:memory:”作為文件名,創(chuàng)建內(nèi)存中的SQLite 數(shù)據(jù)庫(kù)也是可能的。
sqlite數(shù)據(jù)庫(kù) 視頻的介紹就聊到這里吧,感謝你花時(shí)間閱讀本站內(nèi)容,更多關(guān)于sqlite數(shù)據(jù)庫(kù) 視頻,SQLite數(shù)據(jù)庫(kù):輕量級(jí)存儲(chǔ)視頻的首選,后端編程Python3-數(shù)據(jù)庫(kù)編程的信息別忘了在本站進(jìn)行查找喔。
創(chuàng)新互聯(lián)(cdcxhl.com)提供穩(wěn)定的云服務(wù)器,香港云服務(wù)器,BGP云服務(wù)器,雙線云服務(wù)器,高防云服務(wù)器,成都云服務(wù)器,服務(wù)器托管。精選鉅惠,歡迎咨詢:028-86922220。
文章題目:SQLite數(shù)據(jù)庫(kù):輕量級(jí)存儲(chǔ)視頻的首選(sqlite數(shù)據(jù)庫(kù)視頻)
本文網(wǎng)址:http://fisionsoft.com.cn/article/dhcgeej.html


咨詢
建站咨詢
