Python-SQLAlchemy:第1節:SQLAlchemy入門

Mark發表於2019-02-16

下一篇文章:Python-SQLAlchemy:第2節:查詢條件設定

SQLAlchemy是Python程式語言下的一款開源軟體。提供了SQL工具包及物件關係對映(ORM)工具,SQLAlchemy使用MIT許可證發行。它採用簡單的Python語音,為高效和高效能的資料庫訪問設計,實現了完整的企業級持久模型。SQLAlchemy非常關注資料庫的量級和效能。

本節通過一套例子分析SQLAlchemy的使用方法。

使用SQLAlchemy至少需要3部分程式碼,它們分別是定義表、定義資料庫連線、進行增、刪、改、查等邏輯操作。

定義表的例項:

from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column,Integer,String

Base=declarative_base()

class Accout(Base):
    __tablename__=u`accout`

    id=Column(Integer,primary_key=True)
    user_namr=Column(String(50),nullable=False)
    password=Column(String(200),nullable=False)
    title=Column(String(50))
    salary=Column(Integer)

    def is_active(self):
        #假設所有
        return True

    def get_id(self):
        #返回賬號ID,用方法返回屬性值提高了表的封裝性。
        return self.id

    def is_authenticated(self):
        #假設已經通過驗證
        return True

    def is_anonymous(self):
        #具有登陸名和密碼的賬號不是匿名使用者
        return False

解析定義表的程式碼如下:

  • SQLAlchemy表之前必須必須引入sqlalchemy.ext.declarative_base,並定義一個它的例項Base。所有表必須繼承自Base。本例中定義了一個賬戶表類Account。
  • 通過__tablename__屬性定義了表在資料庫中實際的名稱account。
  • 引入sqlalchemy包中的Column、Integer、String型別,因為需要用它們定義表中的列。本例在Account表中定義了5個列,分別是整型id和salary,以及字串型別的user_name、password、title。
  • 在定義列時可以通過給Column傳送引數定義約束。本例中通過primary_key引數將id列定義主鍵,通過nullable引數將user__name和password定義非空。
  • 在表中還可以自定義其他函式。本例中定義了使用者驗證時常用的幾個函式:is__activite()、get__id()、is__authenticate()和is_anonymous()。

定義資料庫連線的示例程式碼如下:

from sqlalchemy import create_engine
from sqlalchemy.orm import scoped_session,sessionmaker
from contextlib import contextmanager

db_connect_string=`mysql://v_user:v_pase@localhost:3306/test_database?charset=utf8`

ssl_args={
    `ssl`:{
        `cert`:`/home/ssl/client-cert.pem`,
        `key`:`/home/shouse/ssl/client-key.pem`,
        `ca`:`/home/shouse/ssl/ca-cert.pem`
    }
}
engine=create_engine(db_connect_string,connect_args=ssl_args)
SessionType=scoped_session(sessionmaker(bind=engine,expire_on_commit=False))
def GetSession():
    return SessionType()

@contextmanager
def session_scope():
    session=GetSession()
    try:
        yield session
        session.commit()
    except:
        session.rollback()
        raise
    finally:
        session.close()

解析此連線資料部分的程式碼如下:

  • 引入資料庫和會話引擎:sqlalchemy.create_engine、sqlalchemy.orm.scoped_session、sqlalchemy.orm.sessionmaker。
  • 定義連線資料庫需要用到的資料庫字串。本例連線MySQL資料庫,字串格式為[databse_type]://[user_name]:[password]@[domain]:[port]/[database]?[parameters]。本例中除了必須的連線資訊,還傳入了charset引數,指定用utf-8編碼方式解碼資料庫中的字串。
  • 用create_engine建立資料庫引擎,如果資料庫開啟了SSL鏈路,則在此處需要傳入ssl客戶端證照的檔案路徑。
  • 用scoped_session(sessionmaker(bind=engine))建立會話型別SessionType,並定義函式GetSession()用以建立SessionType的例項。

至此,已經可以用GetSession()函式建立資料庫會話並進行資料庫操作了。但為了使之後的資料庫操作的程式碼能夠自動進行事務處理,本例中定義了上下文函式session_scope()。在Python中定義上下文函式的方法是為其加入contextlib包中的contextmanager裝飾器。在上下文函式中執行如下邏輯:在函式開始時建立資料庫會話,此時會自動建立一個資料庫事務:當發生異常時回滾(rollback)事務;當退出時關閉(close)連線。在關閉連線時會自動進行事務提交(commit)操作。

進行資料庫操作的程式碼:

from sqlalchemy import or_,orm
def InsertAccount(user,passwd,title,salary): #新增操作
    with session_scope() as session:
        account=orm.Account(user_name=user,passwd=passwd,title=title,salary=salary)
        session.add(account)

def GetAccount(id=None,user_name=None): #查詢操作
    with session_scope() as session:
        return session.query(orm.Account).filter(
            or_(orm.Account.id==id,orm.Account.user_name=user_name)
        ).first()

def DeleteAccount(user_name): #刪除操作
    with session_scope() as session:
        account=GetAccount(user_name=user_name)
        if account:
            session.delete(account)

def UpdateAccount(id,user_name,password,title,salary):  #更新操作
    with session_scope() as session:
        account=session.query(orm.Account).filter(orm.Account.id==id).first()
        if not account:return
        account.user_name=user_name
        account.password=password
        account.salary=salary
        account.title=title


InsertAccount("Mark","123","Manager",3000)  #呼叫新增操作
InsertAccount("帥哥","456","Boss",2000)  #呼叫新增操作
GetAccount(2) #呼叫查詢操作
DeleteAccount("Mark")
UpdateAccount(1,"admin","none","System admin",2500)

本例演示了資料庫中最常用的4種基於記錄的操作:新增、查詢、刪除、更新。對此部分程式碼的解析如下:

  • 用import語句引入資料表(Account)所在的包orm。引入多條件查詢時使用or_。
  • 每個函式中都通過with語句啟用上下文函式session_scope(),通過它獲取到session物件,並自動開啟新事物。
  • 在InsertAccount中,通過新建一個表Account例項,並通過session.add將其新增到資料庫中。由於上下文函式退出時會自動提交事務,所以無需顯示的呼叫session.commit()使新增生效。
  • 在GetAccount中通過query語句進行查詢,查詢條件由filter設定,多個查詢條件可以用or_或and_連線。
  • 在DeleteAccount中通過GetAccount查詢該物件,如果查詢到了,則直接呼叫session.delete()將該物件刪除。
  • 在InsertAccount()中通過query根據id查詢記錄,如果查詢到了,則通過設定物件的屬性實現對記錄的修改。
  • 查詢語句的結果是一個物件集合。查詢語句後面的first()函式用於提取該集合中的第一個物件,如果用all()函式替換first()函式,查詢則會返回該集合。

主流資料庫的連線方式

SQLAlchemy這樣的orm資料庫操作方式可以對業務開發者遮蔽不同資料庫之間的差異,這樣當需要進行資料庫遷移時(比如MySQL遷移到SQLite),則只需要更換資料庫連線字串。

下表列出了SQLAlchemy連線主流資料庫時的資料庫字串的編寫方法:

資料庫 連線字串
Microsoft SQLServer `mssql+pymssql://[user]:[pass]@[domain]:[port]/[dbname]`
MySQL `mysql://[user]:[pass]@[domain]:[port]/[dbname]`
Oracle `oracle://[user]:[pass]@[domain]:[port/[dbname]]`
PostgreSQL `postgresql://[user]:[pass]@[domain]:[port]/[dbname]`
SQLite `sqlite://[file_pathname]`

相關文章