摘要:另外,項(xiàng)目在單元測試中使用的是的內(nèi)存數(shù)據(jù)庫,這樣開發(fā)者運(yùn)行單元測試的時候不需要安裝和配置復(fù)雜的數(shù)據(jù)庫,只要安裝好就可以了。而且,數(shù)據(jù)庫是保存在內(nèi)存中的,會提高單元測試的速度。是實(shí)現(xiàn)層的基礎(chǔ)。項(xiàng)目一般會使用數(shù)據(jù)庫來運(yùn)行單元測試。
OpenStack中的關(guān)系型數(shù)據(jù)庫應(yīng)用
OpenStack中的數(shù)據(jù)庫應(yīng)用主要是關(guān)系型數(shù)據(jù)庫,主要使用的是MySQL數(shù)據(jù)庫。當(dāng)然也有一些NoSQL的應(yīng)用,比如Ceilometer項(xiàng)目。就SQL數(shù)據(jù)庫本身的應(yīng)用而言,OpenStack的項(xiàng)目和其他項(xiàng)目并沒有什么區(qū)別,也是采用ORM技術(shù)對數(shù)據(jù)進(jìn)行增刪改查而已。
本文的重點(diǎn)是講解OpenStack項(xiàng)目中對關(guān)系型數(shù)據(jù)庫的應(yīng)用的基礎(chǔ)知識,更多的是涉及ORM庫的使用。對于數(shù)據(jù)庫的安裝和配置,需要讀者自己查找一下MySQL的教程,如果只是為了驗(yàn)證ORM的相關(guān)知識,也可以使用sqlite數(shù)據(jù)庫。
數(shù)據(jù)庫的選擇OpenStack官方推薦的保存生產(chǎn)數(shù)據(jù)的是MySQL數(shù)據(jù)庫,在devstack項(xiàng)目(這個項(xiàng)目用于快速搭建OpenStack開發(fā)環(huán)境)中也是安裝了MySQL數(shù)據(jù)庫。不過,因?yàn)镺penStack的項(xiàng)目中沒有使用特定的只有在MySQL上才能用的功能,而且所采用的ORM庫SQLAlchemy也支持多種數(shù)據(jù)庫,所以理論上選擇PostgreSQL之類的數(shù)據(jù)庫來替代MySQL也是可行的。
另外,OpenStack項(xiàng)目在單元測試中使用的是sqlite的內(nèi)存數(shù)據(jù)庫,這樣開發(fā)者運(yùn)行單元測試的時候不需要安裝和配置復(fù)雜的MySQL數(shù)據(jù)庫,只要安裝好sqlite3就可以了。而且,數(shù)據(jù)庫是保存在內(nèi)存中的,會提高單元測試的速度。
ORM的選擇 什么是ORMORM的全稱是Object-Relational Mapping,即對象關(guān)系映射,是一種利用編程語言的對象來表示關(guān)系數(shù)據(jù)庫中的數(shù)據(jù)的技術(shù),其更形式化的定義可以參考Wiki頁面Orject-relational mapping。簡單的說,ORM就是把數(shù)據(jù)庫的一張表和編程語言中的一個對象對應(yīng)起來,這樣我們在編程語言中操作一個對象的時候,實(shí)際上就是在操作這張表,ORM(一般是一個庫)負(fù)責(zé)把我們對一個對象的操作轉(zhuǎn)換成對數(shù)據(jù)庫的操作。
Python中的ORM實(shí)現(xiàn)一般來說,各種主流語言都有自己的ORM實(shí)現(xiàn),一般來說也不只一種,比較出名的有Java的Hibernate,Ruby on Rails的ORM,C++的ODB等。在Python中也存在多種ORM的實(shí)現(xiàn),最著名的兩種是Django的Model層的ORM實(shí)現(xiàn),以及SQLAlchemy庫。這兩種ORM實(shí)現(xiàn)基本上是Python中ORM的事實(shí)上的標(biāo)準(zhǔn),如果你寫Django應(yīng)用,那么你就用Django自帶的實(shí)現(xiàn);不然,你就可以選擇SQLAlchemy庫。
OpenStack基本上都是Python項(xiàng)目,所以在OpenStack中,ORM主要是使用了SQLAlchemy庫(Keystone, Nova, Neutron等);不過使用了Django的Horizon項(xiàng)目(面板)還是使用了Django自帶的ORM實(shí)現(xiàn)。本文主要是講解OpenStack中如何使用SQLAlchemy庫,這個也是開發(fā)OpenStack項(xiàng)目的最基本知識。
SQLAlchemy SQLAlchemy簡介SQLAlchemy項(xiàng)目是Python中最著名的ORM實(shí)現(xiàn),不僅在Python項(xiàng)目中也得到了廣泛的應(yīng)用,而且對其他語言的ORM有很大的影響。OpenStack一開始選擇這個庫,也是看中了它足夠穩(wěn)定、足夠強(qiáng)大的特點(diǎn)。
SQLAlchemy項(xiàng)目的官網(wǎng)是http://www.sqlalchemy.org/,目前該項(xiàng)目最新的版本是1.0.11,1.0系列是今年剛發(fā)的,0.9系列應(yīng)該還是應(yīng)用最廣泛的版本。對于一般的應(yīng)用來說,0.9系列和1.0系列差別不大。
關(guān)于SQLAlchemy的學(xué)習(xí)我個人覺得SQLAlchemy的學(xué)習(xí)難度會比Django的Model層難一些,因?yàn)橐粋€最簡單的例子也會有一些不太直觀的地方,對于沒用過的人來說,會比較難以理解。不過SQLAlchemy官網(wǎng)整理了一些比較不錯的入門教程,是一個比較好的學(xué)習(xí)起點(diǎn):Tutorials。另外,官方的Reference其實(shí)是一個很好的教程,講了很多基本的概念,有助于理解SQLAlchemy的庫的使用。Reference的地址是:http://docs.sqlalchemy.org/en/rel_1_0/,還可以直接下載PDF版本。我個人建議大家直接閱讀Reference即可,閱讀順序就按照PDF文件的章節(jié)編排順序進(jìn)行。雖然這個文檔很長,但是我最后發(fā)現(xiàn)這么做是最節(jié)約時間的。
SQLAlchemy的架構(gòu)先讓我們來看一下SQLAlchemy這個庫的總體架構(gòu),如下圖(圖來自官網(wǎng))所示:
SQLAlchemy這個庫分為兩層:
上面這層是ORM層,為用戶提供ORM接口,即通過操作Python對象來實(shí)現(xiàn)數(shù)據(jù)庫操作的接口。
下面這層是Core層,這層包含了Schema/Types, SQL Expression Language, Engine這三個部分:
SQL Expression Language是SQLAlchemy中實(shí)現(xiàn)的一套SQL表達(dá)系統(tǒng),主要是實(shí)現(xiàn)了對SQL的DML(Data Manipulation Language)的封裝。這里實(shí)現(xiàn)了對數(shù)據(jù)庫的SELECT、DELETE、UPDATE等語句的封裝。SQL Expression Language是實(shí)現(xiàn)ORM層的基礎(chǔ)。
Schema/Types這部分主要是實(shí)現(xiàn)了對SQL的DDL(Data Definition Language)的封裝。實(shí)現(xiàn)了Table類用來表示一個表,Column類用來表示一個列,也是實(shí)現(xiàn)了將數(shù)據(jù)庫的數(shù)據(jù)類型映射到Python的數(shù)據(jù)類型。上面的SQL Expression Language的操作對象就是這里定義的Table。
Engine實(shí)現(xiàn)了對各種不同的數(shù)據(jù)庫客戶端的封裝和調(diào)度,是所有SQLAlchemy應(yīng)用程序的入口點(diǎn),要使用SQLAlchemy庫來操作一個數(shù)據(jù)庫,首先就要有一個Engine對象,后續(xù)的所有對數(shù)據(jù)庫的操作都要通過這個Engine對象來進(jìn)行。下圖是官方文檔中的Engine位置的描述圖:
Pool是Engine下面的一個模塊,用來管理應(yīng)用程序到數(shù)據(jù)庫的連接。
Dialect是Engine下的另一個模塊,用來對接不同的數(shù)據(jù)庫驅(qū)動(即DBMS客戶端),這些驅(qū)動要實(shí)現(xiàn)DBAPI接口。
最后,SQLAlchemy還要依賴各個數(shù)據(jù)庫驅(qū)動的DBAPI接口來實(shí)現(xiàn)對數(shù)據(jù)庫服務(wù)的調(diào)用。DBAPI是Python定義的數(shù)據(jù)庫API的實(shí)現(xiàn)規(guī)范,具體見PEP0249。
上面簡單的總結(jié)了SQLAlchemy的架構(gòu),希望大家能夠大概了解一下SQLAlchemy,在后面介紹一些相關(guān)概念時,能夠知道這個概念是屬于整個架構(gòu)的哪個部分。
Dialect和數(shù)據(jù)庫客戶端上面提到了Dialect是用來對接不同的數(shù)據(jù)庫驅(qū)動的,它主要負(fù)責(zé)將SQLAlchemy最后生成的數(shù)據(jù)庫操作轉(zhuǎn)換成對數(shù)據(jù)庫驅(qū)動的調(diào)用,其中會處理一些不同數(shù)據(jù)庫和不同DBAPI實(shí)現(xiàn)的差別。這個部分一般是SQLAlchemy的開發(fā)者關(guān)心的內(nèi)容,如果你只是使用SQLAlchemy來操作數(shù)據(jù)庫,那么可以不用關(guān)心這個部分。不過我們還是要來了解一下SQLAlchemy支持的和OpenStack相關(guān)的數(shù)據(jù)庫驅(qū)動。
MySQLOpenStack項(xiàng)目主要是使用MySQL,之前一直都在使用MySQL-Python驅(qū)動,因?yàn)檫@個驅(qū)動足夠成熟和穩(wěn)定。不過這個情況正在轉(zhuǎn)變,有如下兩個原因:
MySQL-Python不支持Python3,而OpenStack正在轉(zhuǎn)換到Python3的過程中,所以這個驅(qū)動最終是要放棄的。
MySQL-Python是用C語言寫的,不支持eventlet庫的monkey-patch操作,無法被eventlet庫轉(zhuǎn)換成異步操作,所以使用了eventlet庫的到OpenStack項(xiàng)目在使用MySQL數(shù)據(jù)庫時,都是進(jìn)行同步的串行操作,有性能損失。
為了解決這個問題,社區(qū)發(fā)起了一次對新驅(qū)動的評估,主要是評估PyMySQL驅(qū)動:PyMySQL Evaluation。這個評估還在社區(qū)的郵件列表發(fā)起了好幾次討論,到目前為止的結(jié)果是:如果使用Python 2.7,那么繼續(xù)使用MySQL-Python這個驅(qū)動,否則就使用PyMySQL這個驅(qū)動。PyMySQL驅(qū)動是使用純Python寫的,不僅支持Python3而且可以支持eventlet的異步。
SQLite3OpenStack項(xiàng)目一般會使用SQLite3數(shù)據(jù)庫來運(yùn)行單元測試。OpenStack在Python2.7下會使用pysqlite驅(qū)動,不過這個驅(qū)動和標(biāo)準(zhǔn)庫中的sqlite3模塊是一樣的,也就是Python內(nèi)置了SQLite3的驅(qū)動,你無需選擇其他的驅(qū)動。
SQLAlchemy的基本概念和使用使用SQLAlchemy大體上分為三個步驟:連接到數(shù)據(jù)庫,定義數(shù)據(jù)模型,執(zhí)行數(shù)據(jù)操作。
連接到數(shù)據(jù)庫在你的應(yīng)用可以使用數(shù)據(jù)庫前,你要先定義好數(shù)據(jù)庫的連接,包括數(shù)據(jù)庫在哪里,用什么賬號訪問等。所有的這些工作都是通過Engine對象來進(jìn)行的(記得上面提到的Engine了么?)。
數(shù)據(jù)庫URLSQLAlchemy使用URL的方式來指定要訪問的數(shù)據(jù)庫,整個URL的具體格式如下:
dialect+driver://username:password@host:port/database
其中,dialect就是指DBMS的名稱,一般可選的值有:postgresql, mysql, sqlite等。driver就是指驅(qū)動的名稱,如果不指定,SQLAlchemy會使用默認(rèn)值。database就是指DBMS中的一個數(shù)據(jù)庫,一般是指通過CREATE DATABASE語句創(chuàng)建的數(shù)據(jù)庫。其他的參數(shù)就不言而喻了。dialect和driver參數(shù)有很多選擇,具體的可以參考官方文檔:Database URLs
創(chuàng)建Engine對象確定了要連接的數(shù)據(jù)庫信息后,就可以通過create_engine函數(shù)來創(chuàng)建一個Engine對象了。
from sqlalchemy import create_engine engine = create_engine("sqlite://:memory:")
create_engine函數(shù)還支持以下幾個參數(shù):
connect_args:一個字典,用來自定義數(shù)據(jù)庫連接的參數(shù),比如指定客戶端使用的字符編碼。
pool_size和max_overflow:指定連接池的大小。
poolclass:指定連接池的實(shí)現(xiàn)
echo:一個布爾值,用來指定是否打印執(zhí)行的SQL語句到日志中。
還有很多其他的參數(shù),可以參考官方文檔:Engine Configuration。
一般來說,Engine對象會默認(rèn)啟用連接池,會根據(jù)不同的dialect來選擇不同的默認(rèn)值。一般來說,你是不用考慮連接池的配置的,默認(rèn)情況都配置好了。想了解關(guān)于連接池的更多內(nèi)容,請查看官方文檔:Connection Pooling。
使用Engine對象一般來說,應(yīng)用程序的代碼是不直接使用Engine對象的,而是把Engine對象交給ORM去使用,或者創(chuàng)建session對象來使用。不過,我們還是來簡單看一下Engine對象能做什么事情。
應(yīng)用程序可以調(diào)用Engine對象的connect()方法來獲得一個到數(shù)據(jù)庫的連接對象;然后可以在這個連接對象上調(diào)用execute()來執(zhí)行SQL語句,調(diào)用begin()、commit()、rollback()來執(zhí)行事務(wù)操作;調(diào)用close()來關(guān)閉連接。Engine對象也有一些快捷方法來直接執(zhí)行上述操作,避免了每次都要調(diào)用connect()來獲取連接這種繁瑣的代碼,比如engine.execute(), with engine.begin()等。
定義數(shù)據(jù)模型有了數(shù)據(jù)庫連接后,我們就可以來定義數(shù)據(jù)模型了,也就是定義映射數(shù)據(jù)庫表的Python類。在SQLAlchemy中,這是通過Declarative的系統(tǒng)來完成的。
Declarative系統(tǒng)根據(jù)官方文檔的描述,SQLAlchemy一開始是采用下面這種方式來定義ORM的:
首先定義一個映射類,這個類是數(shù)據(jù)庫表在代碼中的對象表示,這類的類屬性是很多Column類的實(shí)例。
然后定義一個Table對象,這里的Table就是上面提到的在Schema/Types模塊中的一個類,用來表示一個數(shù)據(jù)庫中的表。
調(diào)用sqlalchemy.orm.mapper函數(shù)把步驟1中定義的類映射到步驟2中定義的Table。
上面這種方式稱為Classical Mappings,看起來好麻煩啊。所以就有了Declarative系統(tǒng)。這個系統(tǒng)就是一次完成這三個步驟,你只需要定義步驟1中的類即可。這也是現(xiàn)在在SQLAlchemy中使用ORM的方式,無需在使用過去這種麻煩的方法。
要使用Declarative系統(tǒng),你需要為所有映射類創(chuàng)建一個基類,這個基類用來維護(hù)所有映射類的元信息。
from sqlalchemy.ext.declarative import declarative_base Base = declarative_base()定義映射類
現(xiàn)在我們可以開始創(chuàng)建映射類了。假設(shè)我們在數(shù)據(jù)庫中有一個表Person,這個表有兩個列,分別是id和name,那么我們創(chuàng)建的映射類如下:
from sqlalchemy import Column, Integer, String # 這里的基類Base是上面我們通過declarative_base函數(shù)生成的 class Person(Base): __tablename__ = "person" id = Column(Interger, primary_key=True) name = Column(String(250), nullable=False)
這樣我們就定義了一個映射類Person,后續(xù)我們可以通過操作這個類的實(shí)例來實(shí)現(xiàn)對數(shù)據(jù)庫表person的操作。在我們的映射類中,我們使用__tablename__屬性來指定該映射類所對應(yīng)的數(shù)據(jù)庫表,通過Column類實(shí)例的方式來指定數(shù)據(jù)庫的字段。這里,讀者可能會問:我如何能知道Column都能支持哪些類型呢?這個查看官方文檔獲得:Column And Data Types。
因?yàn)槲覀兪褂昧薉eclarative系統(tǒng),所以雖然我們自己沒有定義Table對象,但是Declarative系統(tǒng)幫我們做了,并且?guī)臀覀冋{(diào)用了mapper函數(shù)。因此,當(dāng)我們定義好一個表的映射類后,這個類的__table__屬性就保存了該映射類所映射的Table對象:
In [6]: Person.__table__ Out[6]: Table("person", MetaData(bind=None), Column("id", Integer(), table=, primary_key=True, nullable=False), Column("name", String(length=250), table= , nullable=False), schema=None)
定義映射類是我們使用ORM的最主要的功能之一,不僅可以指定單表的映射,還能夠指定表之間的關(guān)系。由于篇幅限制,我們在本文就不展開講了。
Schema和Metadata關(guān)于Table對象,我們上面也提到了,它屬于SQLAlchemy的core層的Schema/Types這個部分。SQLAlchemy中的Schema可以理解為和DDL相關(guān)的一套體系,它告訴SQLAlchemy的其他部分,數(shù)據(jù)庫中的表是如何定義的。這個相當(dāng)于我們在MySQL中使用describe命令,或者在PostgreSQL中使用d命令。
SQLAlchemy中通過schema metadata來實(shí)現(xiàn)上面說的Schema。Schema metadata,官方文檔中也稱為database metadata,簡稱為metadata,是一個容器,其中包含了和DDL相關(guān)的所有信息,包括Table, Column等對象。當(dāng)SQLAlchemy要根據(jù)映射類生成SQL語句時,它會查詢metadata中的信息,根據(jù)信息來生成SQL語句。
為了要讓metadata可以工作,我們需要把DDL的相關(guān)信息放到metadata中。如果你注意看上面Person.__table__的輸出,就會發(fā)現(xiàn)Table類的第二個參數(shù)就是一個Metadata實(shí)例,也就是說,我們需要在定義Table的時候就把DDL信息放到metadata中。如果是是用classical mapping的方式,我們需要先創(chuàng)建一個metadata實(shí)例,然后每次創(chuàng)建一個Table對象的時候就把metadata傳遞進(jìn)去。從寫代碼的角度來說,這個方式?jīng)]有什么問題,也不算麻煩;問題是我們在使用ORM的過程中,幾乎不會用到metadata,metadata基本上是給SQLAlchemy用的,對于用戶來說metadata提供的接口只能用來創(chuàng)建表和刪除表,這種操作的頻率遠(yuǎn)低于查詢操作。
好在Declarative系統(tǒng)則幫我們把這些都做好了。當(dāng)我們通過declarative_base()生成一個基類Base的時候,這個基類就已經(jīng)包含了一個metadata實(shí)例,后面基于Base定義映射類都會被自動加入到這個metadata中。我們可以通過Base.metadata來訪問這個metadata實(shí)例。
說了這么多關(guān)于metadata的內(nèi)容,簡單總結(jié)一下:metadata是schema在SQLAlchemy中的實(shí)現(xiàn),包含了DDL的信息,SQLAlchemy中的其他部分需要依賴于metadata中的信息,一般用戶很少使用metadata。
很少用?那說這么多是做啥?主要是讓讀者可以理解下面這個語句的原理:
Base = declarative_base() # 基于Base定義映射類 Base.metadata.create_all(engine)
最后這行代碼是我們最常用到metadata的地方:創(chuàng)建所有的表。我們告訴create_all使用哪個engine,它就會生成所有的CREATE TABLE語句,并且通過engine發(fā)送到數(shù)據(jù)庫上執(zhí)行。這個在單元測試的時候很有用。你可以執(zhí)行一下下面的代碼來觀察輸出:
from sqlalchemy import Column, Integer, String from sqlalchemy.ext.declarative import declarative_base from sqlalchemy import create_engine Base = declarative_base() class Person(Base): __tablename__ = "person" id = Column(Integer, primary_key=True) name = Column(String(250), nullable=False) engine = create_engine("sqlite:///:memory:", echo=True) Base.metadata.create_all(engine)
輸出結(jié)果如下:
... 2016-01-06 09:56:03,600 INFO sqlalchemy.engine.base.Engine PRAGMA table_info("person") 2016-01-06 09:56:03,601 INFO sqlalchemy.engine.base.Engine () 2016-01-06 09:56:03,602 INFO sqlalchemy.engine.base.Engine CREATE TABLE person ( id INTEGER NOT NULL, name VARCHAR(250) NOT NULL, PRIMARY KEY (id) ) 2016-01-06 09:56:03,603 INFO sqlalchemy.engine.base.Engine () 2016-01-06 09:56:03,603 INFO sqlalchemy.engine.base.Engine COMMIT
關(guān)于Metadata的更多信息,請查看官方文檔:Schema Definition Language。
會話會話(session)是我們通過SQLAlchemy來操作數(shù)據(jù)庫的入口。我們前面有介紹過SQLAlchemy的架構(gòu),session是屬于ORM層的。Session的功能是管理我們的程序和數(shù)據(jù)庫之間的會話,它利用Engine的連接管理功能來實(shí)現(xiàn)會話。我們在上文有提到,我們創(chuàng)建了Engine對象,但是一般不直接使用它,而是把它交給ORM去使用。其中,通過session來使用Engine就是一個常用的方式。
要是用session,我們需要先通過sessionmaker函數(shù)創(chuàng)建一個session類,然后通過這個類的實(shí)例來使用會話,如下所示:
from sqlalchemy.orm import sessionmaker DBSession = sessionmaker(bind=engine) session = DBSession()
我們通過sessionmaker的bind參數(shù)把Engine對象傳遞給DBSession去管理。然后,DBSession實(shí)例化的對象session就能被我們使用了。
CRUDCRUD就是CREATE, READ, UPDATE, DELETE,增刪改查。這個也是SQLAlchemy中最常用的功能,而且都是通過上一小節(jié)中的session對象來使用的。我們這簡單的介紹一下這四個操作,后面會給出官方文檔的位置。
Create在數(shù)據(jù)庫中插入一條記錄,是通過session的add()方法來實(shí)現(xiàn)的,你需要先創(chuàng)建一個映射類的實(shí)例,然后調(diào)用session.add()方法,然后調(diào)用session.commit()方法提交你的事務(wù)(關(guān)于事務(wù),我們下面會專門講解):
new_person = Person(name="new person") session.add(new_person) session.commit()Delete
刪除操作和創(chuàng)建操作差不多,是把一個映射類實(shí)例傳遞給session.delete()方法。
Update更新一條記錄需要先使用查詢操作獲得一條記錄對應(yīng)的對象,然后修改對象的屬性,再通過session.add()方法來完成更新操作。
Read查詢操作,一般稱為query,在SQLAlchemy中一般是通過Query對象來完成的。我們可以通過session.query()方法來創(chuàng)建一個Query對象,然后調(diào)用Query對象的眾多方法來完成查詢操作。
事務(wù)使用session,就會涉及到事務(wù),我們的應(yīng)用程序也會有很多事務(wù)操作的要求。當(dāng)你調(diào)用一個session的方法,導(dǎo)致session執(zhí)行一條SQL語句時,它會自動開始一個事務(wù),直到你下次調(diào)用session.commit()或者session.rollback(),它就會結(jié)束這個事務(wù)。你也可以顯示的調(diào)用session.begin()來開始一個事務(wù),并且session.begin()還可以配合Python的with來使用。
會話, CRUD, 事務(wù)的小結(jié)上面關(guān)于session, CRUD和事務(wù)的內(nèi)容寫的比較少,因?yàn)檫@些功能的內(nèi)容很多,而且官方文檔也寫得很全面,本文就不做一些重復(fù)說明了。我們會在下一篇文章中通過webdemo的代碼來看看如何使用這些功能。
Session的文檔
官方文檔中關(guān)于CRUD操作的教程
Session中的事務(wù)管理
總結(jié)本文介紹了OpenStack中和數(shù)據(jù)庫相關(guān)的一些知識,重點(diǎn)講解了SQLAlchemy這個庫的基本概念和架構(gòu)。下一篇文章,我們會通過demo來實(shí)際項(xiàng)目中如何使用SQLAlchemy。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/45410.html
摘要:通過,也就是通過各個項(xiàng)目提供的來使用各個服務(wù)的功能。通過使用的方式是由各個服務(wù)自己實(shí)現(xiàn)的,比如負(fù)責(zé)計(jì)算的項(xiàng)目實(shí)現(xiàn)了計(jì)算相關(guān)的,負(fù)責(zé)認(rèn)證的項(xiàng)目實(shí)現(xiàn)了認(rèn)證和授權(quán)相關(guān)的。的服務(wù)都是使用的方式來部署的。 使用OpenStack服務(wù)的方式 OpenStack項(xiàng)目作為一個IaaS平臺,提供了三種使用方式: 通過Web界面,也就是通過Dashboard(面板)來使用平臺上的功能。 通過命令行,也就...
摘要:本文將進(jìn)入單元測試的部分,這也是基礎(chǔ)知識中最后一個大塊。本文將重點(diǎn)講述和中的單元測試的生態(tài)環(huán)境。另外,在中指定要運(yùn)行的單元測試用例的完整語法是。中使用模塊管理單元測試用例。每個項(xiàng)目的單元測試代碼結(jié)構(gòu)可 本文將進(jìn)入單元測試的部分,這也是基礎(chǔ)知識中最后一個大塊。本文將重點(diǎn)講述Python和OpenStack中的單元測試的生態(tài)環(huán)境。 單元測試的重要性 github上有個人畫了一些不同語言的學(xué)...
摘要:不幸的是,在軟件包管理十分混亂,至少歷史上十分混亂。的最大改進(jìn)是將函數(shù)的參數(shù)單獨(dú)放到一個的文件中這些成為包的元數(shù)據(jù)。基于的版本號管理。的版本推導(dǎo)這里重點(diǎn)說明一下基于的版本號管理這個功能。開發(fā)版本號的形式如下。 為什么寫這個系列 OpenStack是目前我所知的最大最復(fù)雜的基于Python項(xiàng)目。整個OpenStack項(xiàng)目包含了數(shù)十個主要的子項(xiàng)目,每個子項(xiàng)目所用到的庫也不盡相同。因此,對于...
摘要:在實(shí)際項(xiàng)目中,這么做肯定是不行的實(shí)際項(xiàng)目中不會使用內(nèi)存數(shù)據(jù)庫,這種數(shù)據(jù)庫一般只是在單元測試中使用。接下來,我們將會了解中單元測試的相關(guān)知識。 在上一篇文章,我們介紹了SQLAlchemy的基本概念,也介紹了基本的使用流程。本文我們結(jié)合webdemo這個項(xiàng)目來介紹如何在項(xiàng)目中使用SQLAlchemy。另外,我們還會介紹數(shù)據(jù)庫版本管理的概念和實(shí)踐,這也是OpenStack每個項(xiàng)目都需要做的...
摘要:到這里,我們的服務(wù)的框架已經(jīng)搭建完成,并且測試服務(wù)器也跑起來了。上面的代碼也就可以修改為再次運(yùn)行我們的測試服務(wù)器,就可以返現(xiàn)返回值為格式了。我們先來完成利用來檢查返回值的代碼方法的第一個參數(shù)表示返回值的類型這樣就完成了的返回值檢查了。 上一篇文章說到,我們將以實(shí)例的形式來繼續(xù)講述這個API服務(wù)的開發(fā)知識,這里會使用Pecan和WSME兩個庫。 設(shè)計(jì)REST API 要開發(fā)REST AP...
閱讀 3667·2023-04-26 02:07
閱讀 3172·2021-09-22 15:55
閱讀 2544·2021-07-26 23:38
閱讀 3124·2019-08-29 15:16
閱讀 2017·2019-08-29 11:16
閱讀 1758·2019-08-29 11:00
閱讀 3596·2019-08-26 18:36
閱讀 3169·2019-08-26 13:32