1. 程式人生 > >Python 數據庫操作 SQLAlchemy

Python 數據庫操作 SQLAlchemy

工廠類 data 取出 拼接 完全 操作 定義 hibernate info

程序在運行過程中所有的的數據都存儲在內存 (RAM) 中,「RAM 是易失性存儲器,系統掉電後 RAM 中的所有數據將全部丟失」。在大多數情況下我們希望程序運行中產生的數據能夠長久的保存,此時我們就需要將數據保存到磁盤上,無論是保存到本地磁盤,還是通過網絡保存到服務器上,最終都會將數據寫入磁盤文件。將數據保存在磁盤中我們需要面對一個數據格式的問題,此時就需要引入數據庫操作。python學習關註我們企鵝qun: 8393 83765 各類入門學習資料免費分享哦!

數據庫是專門用於數據的集中存儲和查詢的軟件,它便於程序保存和讀取數據,且能夠通過特定的條件查詢指定的數據。

數據庫原理請參考如果有人問你數據庫的原理,叫他看這篇文章。

Python 的標準數據庫接口為 Python DB-API,它為編程人員提供了完善的數據庫應用標稱接口。但是使用 Python DB-API 需要開發人員自行去拼接 SQL,並把 SQL 做成模板。此時全靠編程人員來保證系統的安全性,完全有人來保證系統的安全性,不可避免的會出現錯誤,為了減少人為原因產生的錯誤 ORM 框架應運而生。

ORM 即 Object-Relational Mapping,把關系數據庫的表結構映射到對象上面。負責這個轉換過程的就是 ORM 框架
Python 中的 ORM 框架主要有 SQLObject、Storm、Django‘s ORM、peewee、SQLALchemy。每種 ORM 框架都有各自的特點和相應的應用範圍,本文主要介紹 SALALchemy,若你對其他框架感興趣請自行搜索相關內容。

SQLAlchemy 簡介

SQLAlchemy 是一個功能強大的開源 Python ORM 工具包。它提供了 “一個知名企業級的持久化模式的,專為高效率和高性能的數據庫訪問設計的,改編成一個簡單的 Python 域語言的完整套件”。它采用了數據映射模式(像 Java 中的 Hibernate)而不是 Active Record 模式(像Ruby on Rails 的 ORM)。

SQLAlchemy官網。
SQLAlchemy 的優缺點:

優點:

企業級 API,使得代碼有健壯性和適應性。
靈活的設計,使得能輕松完成復雜的數據查詢。
缺點:

工作單元概念不常見。
重量級 API,導致長學習曲線。
SQLAlchemy 應用

以下是一段使用 SQLAlchemy 操作 SQLite 數據庫的代碼

-- coding:utf-8 --

from sqlalchemy import (
create_engine,
Column,
Integer,
String,
)
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
engine = create_engine(‘sqlite:///./sqlalchemy.sqlite‘, echo=True)
Base = declarative_base()
class User(Base):
tablename = ‘users‘
id = Column(Integer, primary_key=True, autoincrement=True)
name = Column(String)
fullname = Column(String)
nickname = Column(String)
def repr(self):
return "<User(name=‘%s‘, fullname=‘%s‘, nickname=‘%s‘)>" % (self.name, self.fullname, self.nickname)
db_session = sessionmaker(bind=engine)
session = db_session()
Base.metadata.create_all(engine)
user1 = User(name=‘ed‘, fullname=‘Ed Jones‘, nickname=‘edsnickname‘)
user2 = User(name=‘wendy‘, fullname=‘Wendy Williams‘, nickname=‘windy‘)
user3 = User(name=‘mary‘, fullname=‘Mary Contrary‘, nickname=‘mary‘)
session.add(user1)
session.add(user2)
session.add(user3)
session.commit()
user = session.query(User).filter(User.id<2).all()
print(user)
user = session.query(User).filter(User.id<=5).all()
print(user)
user1.name = ‘admin‘
session.merge(user1)
user4 = User(name=‘fred‘, fullname=‘Fred Flintstone‘, nickname=‘freddy‘)
session.merge(user4)
session.query(User).filter(User.id==2).update({‘name‘:‘test‘})
user = session.query(User).filter(User.id<=5).all()
print(user)
在以上代碼中我們完成了一下工作:

連接到數據庫「本次我們使用的是 SQLite 數據庫」。
創建數據庫表並將其映射到 Python 類上。
創建數據實例,並將其保存到數據庫中。
對保存在數據庫中的數據進行讀取和修改。
導入 SQLAlchemy 模塊並連接到 SQLite 數據庫

SQLAlchemy 通過 create_engine 函數來創建數據庫連接。create_engine 函數的第一個參數是數據了 URL,第二個參數 echo 設置為 True 表示在程序的運行過程中我們可以在控制臺看到操作所涉及到的 SQL 語句。

在本次示例中我們使用的數據庫是 SQLite,你也可以使用其他數據庫。只有在調試狀態下將 echo 設置為 True,在生產環境請將 echo 設置為 false 或省略 echo 參數。
engine = create_engine(‘sqlite:///./sqlalchemy.sqlite‘, echo=True)
create_engine 返回的是一個 Engine 實例,它指向數據庫的一些核心接口。SQLAlchemy會根據你選擇的數據庫配置而調用對應的 DB-API。

create_engine 函數並會不真正建立數據庫的 DB-API 連接,當調用 Engine.execute() 或 Engine.connect() 方法時才會建立連接。大多數情況下我們無需關註 Engine,SQLAlchemy 會幫我們處理。
創建數據庫表

將 python 類映射到數據庫表上,這個 Python 類需要時一個指定基類的子類,這個基類應當含有ORM映射中相關的類和表的信息。這個基類可以通過 declarative_base 方法來創建。

Base = declarative_base()
在這個示例中使用 Base 基類創建了一個 User 的類來作為數據庫表。

class User(Base):
tablename = ‘users‘
id = Column(Integer, primary_key=True, autoincrement=True)
name = Column(String)
fullname = Column(String)
nickname = Column(String)
def repr(self):
return "<User(name=‘%s‘, fullname=‘%s‘, nickname=‘%s‘)>" % (self.name, self.fullname, self.nickname)
在 User 類中我們定義了需要映射到數據庫表上的屬性,主要包括表名稱、列的類型和名稱等。這個類至少應包含一個名為 tablename 的屬性來給出數據庫表的名稱,及至少一個給出表的主鍵「primary key」的列。在 User 類中我們定義了表名稱為 users,定義了 id、name、fullname、nickname 四列數據,並設置 id 為表的主鍵。

創建完成 User 類後,實際在 SQLite 數據庫中並不存在該表,此時需要使用 declarative 基類的 Metadata.create_all 在數據庫中創建 users 表,在 create_all 方法中我們需要傳入參數 Engine。

通過 Metadata.create_all 傳入的 Engine 參數,SQLAlchemy 自動實現對數據庫的連接。
Base.metadata.create_all(engine)
metadata.create_all 方法執行完成後在 SQLite 數據庫即可查到名稱為 users 的數據表。

保存數據實例到數據庫中

將數據保存到數據庫中,我們需要 User 的實例和用於操作數據的 session。

session 是 ORM 數據的接口,可以通過 session 來操作數據庫中的數據。
使用已經定義完成的 User 類將數據實例化。

user1 = User(name=‘ed‘, fullname=‘Ed Jones‘, nickname=‘edsnickname‘)
user2 = User(name=‘wendy‘, fullname=‘Wendy Williams‘, nickname=‘windy‘)
user3 = User(name=‘mary‘, fullname=‘Mary Contrary‘, nickname=‘mary‘)
獲取 session 首先需要使用 sessionmaker 來得到 session 的工廠類,然後通過工廠類來獲取 session。

db_session = sessionmaker(bind=engine)
session = db_session()
session 通過 Engine 與數據庫進行關聯。session 創建完成後並不會立即打開與數據庫的連接,只有當我們第一使用 session 是,才會從 Engine 維護的連接池中取出一個連接來操作數據庫,這個連接在我們關閉 session 時會被釋放。

獲取 session 後可以通過 add 和 commit 方法將數據保存到數據庫中。

session.add(user1)
session.add(user2)
session.add(user3)
session.commit()
對數據庫中的數據進行查詢和修改

SQLAlchemy 通過 query 來對數據進行查詢,可以通過 filter 方法對查詢結果進行篩選。

user = session.query(User).filter(User.id<2).all()
print(user)
user = session.query(User).filter(User.id<=5).all()
print(user)
以上代碼通過 query 獲取數據庫中所有 User 數據,然後通過 filter 方法篩選出 id 小於 2 和 id 小於等於 5 的數據。

數據庫的修改可以通過 merge 和 update 來實現

user1.name = ‘admin‘
session.merge(user1)
user4 = User(name=‘fred‘, fullname=‘Fred Flintstone‘, nickname=‘freddy‘)
session.merge(user4)
session.query(User).filter(User.id==2).update({‘name‘:‘test‘})
user = session.query(User).filter(User.id<=5).all()
print(user)
使用 merge 修改數據,當數據中存在該數據時修改,不存在是將當前數據插入數據庫中。
代碼運行結果

以上示例代碼的運行結果如下

2019-02-16 21:45:23,919 INFO sqlalchemy.engine.base.Engine SELECT CAST(‘test plain returns‘ AS VARCHAR(60)) AS anon_1
2019-02-16 21:45:23,919 INFO sqlalchemy.engine.base.Engine ()
2019-02-16 21:45:23,919 INFO sqlalchemy.engine.base.Engine SELECT CAST(‘test unicode returns‘ AS VARCHAR(60)) AS anon_1
2019-02-16 21:45:23,919 INFO sqlalchemy.engine.base.Engine ()
2019-02-16 21:45:23,920 INFO sqlalchemy.engine.base.Engine PRAGMA table_info("users")
2019-02-16 21:45:23,920 INFO sqlalchemy.engine.base.Engine ()
2019-02-16 21:45:23,921 INFO sqlalchemy.engine.base.Engine
CREATE TABLE users (
id INTEGER NOT NULL,
name VARCHAR,
fullname VARCHAR,
nickname VARCHAR,
PRIMARY KEY (id)
)
2019-02-16 21:45:23,921 INFO sqlalchemy.engine.base.Engine ()
2019-02-16 21:45:23,922 INFO sqlalchemy.engine.base.Engine COMMIT
2019-02-16 21:45:23,924 INFO sqlalchemy.engine.base.Engine BEGIN (implicit)
2019-02-16 21:45:23,925 INFO sqlalchemy.engine.base.Engine INSERT INTO users (name, fullname, nickname) VALUES (?, ?, ?)
2019-02-16 21:45:23,925 INFO sqlalchemy.engine.base.Engine (‘ed‘, ‘Ed Jones‘, ‘edsnickname‘)
2019-02-16 21:45:23,926 INFO sqlalchemy.engine.base.Engine INSERT INTO users (name, fullname, nickname) VALUES (?, ?, ?)
2019-02-16 21:45:23,926 INFO sqlalchemy.engine.base.Engine (‘wendy‘, ‘Wendy Williams‘, ‘windy‘)
2019-02-16 21:45:23,926 INFO sqlalchemy.engine.base.Engine INSERT INTO users (name, fullname, nickname) VALUES (?, ?, ?)
2019-02-16 21:45:23,926 INFO sqlalchemy.engine.base.Engine (‘mary‘, ‘Mary Contrary‘, ‘mary‘)
2019-02-16 21:45:23,927 INFO sqlalchemy.engine.base.Engine COMMIT
2019-02-16 21:45:23,929 INFO sqlalchemy.engine.base.Engine BEGIN (implicit)
2019-02-16 21:45:23,929 INFO sqlalchemy.engine.base.Engine SELECT users.id AS users_id, users.name AS users_name, users.fullname AS users_fullname, users.nickname AS users_nickname
FROM users
WHERE users.id < ?
2019-02-16 21:45:23,929 INFO sqlalchemy.engine.base.Engine (2,)
[<User(name=‘ed‘, fullname=‘Ed Jones‘, nickname=‘edsnickname‘)>]
2019-02-16 21:45:23,931 INFO sqlalchemy.engine.base.Engine SELECT users.id AS users_id, users.name AS users_name, users.fullname AS users_fullname, users.nickname AS users_nickname
FROM users
WHERE users.id <= ?
2019-02-16 21:45:23,931 INFO sqlalchemy.engine.base.Engine (5,)
[<User(name=‘ed‘, fullname=‘Ed Jones‘, nickname=‘edsnickname‘)>, <User(name=‘wendy‘, fullname=‘Wendy Williams‘, nickname=‘windy‘)>, <User(name=‘mary‘, fullname=‘Mary Contrary‘, nickname=‘mary‘)>]
2019-02-16 21:45:23,932 INFO sqlalchemy.engine.base.Engine UPDATE users SET name=? WHERE users.id = ?
2019-02-16 21:45:23,932 INFO sqlalchemy.engine.base.Engine (‘admin‘, 1)
2019-02-16 21:45:23,933 INFO sqlalchemy.engine.base.Engine INSERT INTO users (name, fullname, nickname) VALUES (?, ?, ?)
2019-02-16 21:45:23,933 INFO sqlalchemy.engine.base.Engine (‘fred‘, ‘Fred Flintstone‘, ‘freddy‘)
2019-02-16 21:45:23,934 INFO sqlalchemy.engine.base.Engine UPDATE users SET name=? WHERE users.id = ?
2019-02-16 21:45:23,934 INFO sqlalchemy.engine.base.Engine (‘test‘, 2)
2019-02-16 21:45:23,935 INFO sqlalchemy.engine.base.Engine SELECT users.id AS users_id, users.name AS users_name, users.fullname AS users_fullname, users.nickname AS users_nickname
FROM users
WHERE users.id <= ?
2019-02-16 21:45:23,935 INFO sqlalchemy.engine.base.Engine (5,)
[<User(name=‘admin‘, fullname=‘Ed Jones‘, nickname=‘edsnickname‘)>, <User(name=‘test‘, fullname=‘Wendy Williams‘, nickname=‘windy‘)>, <User(name=‘mary‘, fullname=‘Mary Contrary‘, nickname=‘mary‘)>, <User(name=‘fred‘, fullname=‘Fred Flintstone‘, nickname=‘freddy‘)>]
由於我們設置 create_engine 中 echo 為 True,因此在執行結果中包含了 SQLAlchemy 打印的 SQL 語句,我們可以取消 crete_engine 中的 echo

engine = create_engine(‘sqlite:///./sqlalchemy.sqlite‘)
此時的執行結果如下:

[<User(name=‘ed‘, fullname=‘Ed Jones‘, nickname=‘edsnickname‘)>]
[<User(name=‘ed‘, fullname=‘Ed Jones‘, nickname=‘edsnickname‘)>, <User(name=‘wendy‘, fullname=‘Wendy Williams‘, nickname=‘windy‘)>, <User(name=‘mary‘, fullname=‘Mary Contrary‘, nickname=‘mary‘)>]
[<User(name=‘admin‘, fullname=‘Ed Jones‘, nickname=‘edsnickname‘)>, <User(name=‘test‘, fullname=‘Wendy Williams‘, nickname=‘windy‘)>, <User(name=‘mary‘, fullname=‘Mary Contrary‘, nickname=‘mary‘)>, <User(name=‘fred‘, fullname=‘Fred Flintstone‘, nickname=‘freddy‘)>]
當取消 echo 後,程序運行結果中原有的 SQL 語句消失。

本文只是對 SQLAlchemy 的使用進行簡單的介紹,SQLAlchemy 本身還有很多特性和運用方法我們可以共同探討。

好啦,如果你跟我一樣都喜歡python,想成為一名優秀的程序員,也在學習python的道路上奔跑,歡迎你加入python學習群:839383765 群內每天都會分享最新業內資料,分享python免費課程,共同交流學習,讓學習變(編)成(程)一種習慣!

Python 數據庫操作 SQLAlchemy