數據庫表是一個二維表,包含多行多列。把一個表的內容用Python的數據結構表示出來的話,可以用一個list表示多行,list的每一個元素是tuple,表示一行記錄,比如,包含`id`和`name`的`user`表:
~~~
[
('1', 'Michael'),
('2', 'Bob'),
('3', 'Adam')
]
~~~
Python的DB-API返回的數據結構就是像上面這樣表示的。
但是用tuple表示一行很難看出表的結構。如果把一個tuple用class實例來表示,就可以更容易地看出表的結構來:
~~~
class User(object):
def __init__(self, id, name):
self.id = id
self.name = name
[
User('1', 'Michael'),
User('2', 'Bob'),
User('3', 'Adam')
]
~~~
這就是傳說中的ORM技術:Object-Relational Mapping,把關系數據庫的表結構映射到對象上。是不是很簡單?
但是由誰來做這個轉換呢?所以ORM框架應運而生。
在Python中,最有名的ORM框架是SQLAlchemy。我們來看看SQLAlchemy的用法。
首先通過pip安裝SQLAlchemy:
~~~
$ pip install sqlalchemy
~~~
然后,利用上次我們在MySQL的test數據庫中創建的`user`表,用SQLAlchemy來試試:
第一步,導入SQLAlchemy,并初始化DBSession:
~~~
# 導入:
from sqlalchemy import Column, String, create_engine
from sqlalchemy.orm import sessionmaker
from sqlalchemy.ext.declarative import declarative_base
# 創建對象的基類:
Base = declarative_base()
# 定義User對象:
class User(Base):
# 表的名字:
__tablename__ = 'user'
# 表的結構:
id = Column(String(20), primary_key=True)
name = Column(String(20))
# 初始化數據庫連接:
engine = create_engine('mysql+mysqlconnector://root:password@localhost:3306/test')
# 創建DBSession類型:
DBSession = sessionmaker(bind=engine)
~~~
以上代碼完成SQLAlchemy的初始化和具體每個表的class定義。如果有多個表,就繼續定義其他class,例如School:
~~~
class School(Base):
__tablename__ = 'school'
id = ...
name = ...
~~~
`create_engine()`用來初始化數據庫連接。SQLAlchemy用一個字符串表示連接信息:
~~~
'數據庫類型+數據庫驅動名稱://用戶名:口令@機器地址:端口號/數據庫名'
~~~
你只需要根據需要替換掉用戶名、口令等信息即可。
下面,我們看看如何向數據庫表中添加一行記錄。
由于有了ORM,我們向數據庫表中添加一行記錄,可以視為添加一個`User`對象:
~~~
# 創建session對象:
session = DBSession()
# 創建新User對象:
new_user = User(id='5', name='Bob')
# 添加到session:
session.add(new_user)
# 提交即保存到數據庫:
session.commit()
# 關閉session:
session.close()
~~~
可見,關鍵是獲取session,然后把對象添加到session,最后提交并關閉。`DBSession`對象可視為當前數據庫連接。
如何從數據庫表中查詢數據呢?有了ORM,查詢出來的可以不再是tuple,而是`User`對象。SQLAlchemy提供的查詢接口如下:
~~~
# 創建Session:
session = DBSession()
# 創建Query查詢,filter是where條件,最后調用one()返回唯一行,如果調用all()則返回所有行:
user = session.query(User).filter(User.id=='5').one()
# 打印類型和對象的name屬性:
print('type:', type(user))
print('name:', user.name)
# 關閉Session:
session.close()
~~~
運行結果如下:
~~~
type: <class '__main__.User'>
name: Bob
~~~
可見,ORM就是把數據庫表的行與相應的對象建立關聯,互相轉換。
由于關系數據庫的多個表還可以用外鍵實現一對多、多對多等關聯,相應地,ORM框架也可以提供兩個對象之間的一對多、多對多等功能。
例如,如果一個User擁有多個Book,就可以定義一對多關系如下:
~~~
class User(Base):
__tablename__ = 'user'
id = Column(String(20), primary_key=True)
name = Column(String(20))
# 一對多:
books = relationship('Book')
class Book(Base):
__tablename__ = 'book'
id = Column(String(20), primary_key=True)
name = Column(String(20))
# “多”的一方的book表是通過外鍵關聯到user表的:
user_id = Column(String(20), ForeignKey('user.id'))
~~~
當我們查詢一個User對象時,該對象的books屬性將返回一個包含若干個Book對象的list。
### 小結
ORM框架的作用就是把數據庫表的一行記錄與一個對象互相做自動轉換。
正確使用ORM的前提是了解關系數據庫的原理。
### 參考源碼
[do_sqlalchemy.py](https://github.com/michaelliao/learn-python3/blob/master/samples/db/do_sqlalchemy.py)
- 關于
- Python簡介
- 安裝Python
- Python解釋器
- 第一個Python程序
- 使用文本編輯器
- Python代碼運行助手
- 輸入和輸出
- Python基礎
- 數據類型和變量
- 字符串和編碼
- 使用list和tuple
- 條件判斷
- 循環
- 使用dict和set
- 函數
- 調用函數
- 定義函數
- 函數的參數
- 遞歸函數
- 高級特性
- 切片
- 迭代
- 列表生成式
- 生成器
- 迭代器
- 函數式編程
- 高階函數
- 返回函數
- 匿名函數
- 裝飾器
- 偏函數
- 模塊
- 使用模塊
- 安裝第三方模塊
- 面向對象編程
- 類和實例
- 訪問限制
- 繼承和多態
- 獲取對象信息
- 實例屬性和類屬性
- 面向對象高級編程
- 使用slots
- 使用@property
- 多重繼承
- 定制類
- 使用枚舉類
- 使用元類
- 錯誤、調試和測試
- 錯誤處理
- 調試
- 單元測試
- 文檔測試
- IO編程
- 文件讀寫
- StringIO和BytesIO
- 操作文件和目錄
- 序列化
- 進程和線程
- 多進程
- 多線程
- ThreadLocal
- 進程 vs. 線程
- 分布式進程
- 正則表達式
- 常用內建模塊
- datetime
- collections
- base64
- struct
- hashlib
- itertools
- XML
- HTMLParser
- urllib
- 常用第三方模塊
- PIL
- virtualenv
- 圖形界面
- 網絡編程
- TCP/IP簡介
- TCP編程
- UDP編程
- 電子郵件
- SMTP發送郵件
- POP3收取郵件
- 訪問數據庫
- 使用SQLite
- 使用MySQL
- 使用SQLAlchemy
- Web開發
- HTTP協議簡介
- HTML簡介
- WSGI接口
- 使用Web框架
- 使用模板
- 異步IO
- 協程
- asyncio
- aiohttp
- 實戰
- Day 1 - 搭建開發環境
- Day 2 - 編寫Web App骨架
- Day 3 - 編寫ORM
- Day 4 - 編寫Model
- Day 5 - 編寫Web框架
- Day 6 - 編寫配置文件
- Day 7 - 編寫MVC
- Day 8 - 構建前端
- Day 9 - 編寫API
- Day 10 - 用戶注冊和登錄
- Day 11 - 編寫日志創建頁
- Day 12 - 編寫日志列表頁
- Day 13 - 提升開發效率
- Day 14 - 完成Web App
- Day 15 - 部署Web App
- Day 16 - 編寫移動App
- FAQ
- 期末總結