像物件一樣對待資料

Crossin先生發表於2019-02-12

我們們程式設計教室有不少同學,學完了基礎課程,掌握了一定的程式設計能力,開始做專案了。然後很可能遇到一個問題:管理資料。課程裡有講過用檔案儲存資料,還有 picklecsv 等模組輔助。但對於稍微複雜一點的資料,往往不夠方便。成熟的解決方案就是使用資料庫

估計每個剛剛使用資料庫的人都會被坑得遍體鱗傷。對於一個剛剛學會 Python 不久的開發新手來說,使用資料庫的 SQL 語句幾乎相當於再學一種新的語言。雖然 sqlitepymysql 等模組提供了與資料的連線,但仍然需要自己去拼接 SQL 語句。Python 語法和 SQL 語法、各種引號、百分號、轉義字元混雜在一起的酸爽,用過的人都忘不了。

所以實際開發中,如無特殊需求,一般不會直接寫 SQL,而是用更為方便的 ORM(物件關係對映,Object Relational Mapping)。顧名思義,就是將關係型資料庫與 Python 中的物件關聯起來,提供了一種運算元據的簡便方式,相當於對資料庫加了一層更友好的介面。

目前 Python 中比較流行的 ORM 解決方案有三種:

  1. Django ORM。使用方便,但很難脫離 Django 單獨使用。
  2. SQLAlchemy。功能強大,成熟可擴充套件,但學習門檻較高。
  3. peewee。輕量,可擴充套件,易學習,但功能有限。

對於偏初級的小型專案,通常用不到很複雜的功能,這時候 peewee 或許是最好的選擇。今天我們就來重點介紹下 peewee 這個 Python ORM 庫。

> 安裝

pip install peewee
複製程式碼

> 連線資料庫

以 SQLite 為例:

import peewee
db = peewee.SqliteDatabase(`people.db`)
db.connect()
複製程式碼

people.db 是 SQLite 的資料庫檔案,如果不存在會自己新建。

如果是 MySQL,要稍微複雜點,需再提供地址、使用者名稱、密碼等資訊,並且必須先手動建好庫:

db = peewee.MySQLDatabase(`people`, host=`127.0.0.1`, user=`root`, passwd=``, charset=`utf8`, port=3306)
複製程式碼

特別要記住的一點是,程式碼進行完所有資料庫操作後,要主動關閉資料庫:

db.close()
複製程式碼

> 建立資料型別

既然是與物件關聯,自然需要以物件導向的方式定義資料結構。我們假定一個表示人的型別 Person,包含姓名 name 和生日 birthday 兩個欄位:

class Person(peewee.Model):
    class Meta:
        database = db
    name = peewee.CharField()
    birthday = peewee.DateField()
複製程式碼

Person.create_table() 複製程式碼

如果是用過 Django 的同學,對這個 Model 應該非常熟悉了。要注意的就是,需要在 Meta 裡定義 database 為前面建立的資料庫。然後使用相應的 Field 型別定義欄位即可。

> 新增資料物件

from datetime import date
# 方法1
uncle_bob = Person(name=`Bob`, birthday=date(1960, 1, 15))
uncle_bob.save()
# 方法2
Person.create(name=`Crossin`, birthday=date(1985, 5, 5))
複製程式碼

直接建立資料物件,需要呼叫 save 方法儲存到資料庫中。而使用 create 方法建立則不用。

> 查詢資料物件

bob = Person.get(Person.name == `Bob`)
print(bob.name, bob.birthday)
# 獲取所有資料
for person in Person.select():
print(person.name)
複製程式碼

注意這裡的查詢條件寫法,這與 Django 是不同的。查詢還可以用 where 語句,這裡不做演示,可以參考官方文件。

> 修改資料物件

對於上一步找到的 bob 變數:

bob.name = `Robert`
bob.save()
複製程式碼

直接向屬性賦值,修改完記得要 save

> 刪除資料物件

bob.delete_instance()
複製程式碼

順便說句,一般不建議在資料庫裡刪除資料,因為資料刪了就不好找回來了,而且可能還會引發關聯資料的報錯。通常是增加一個 is_deleted 欄位標記已刪除的內容。(所以,不要以為在網上把釋出過的內容刪掉就真的不存在了)

> 建立關聯資料

在程式中,經常會有一些具有關聯關係的資料。比如我們再建立一個寵物類 Pet,每個寵物有名字 name 和主人 owner。owner 對應的就是我們前面建立的 Person 類:

class Pet(peewee.Model):
class Meta:
database = db
owner = peewee.ForeignKeyField(Person, backref=`pets`)
name = peewee.CharField()
複製程式碼

這樣一來,我們就可以很方便的通過寵物找到它的主人:

bob_kitty = Pet.create(owner=bob, name=`Kitty`)
bob_fido = Pet.create(owner=bob, name=`Fido`)
print(bob_kitty.owner.name)
複製程式碼

也可以找到一個人養的所有寵物:

for pet in bob.pets:
print(pet.name)
複製程式碼

以上就是 peewee 的基本操作,如果你瞭解物件導向,應該不難理解。這些例子取自其官方文件的快速上手 Quickstart。雖然沒有像 Requests 那樣貼心地提供中文版,但也同樣足夠人性化。

地址:docs.peewee-orm.com/en/

> 自動生成程式碼

peewee 提供了一個功能,可以從已有的資料庫反向生成資料模型程式碼。以 SQLite 為例:

python -m pwiz -e sqlite people.db > db.py
複製程式碼

在你的資料庫檔案所在路徑下執行這條命令,就可以在 db.py 中自動生成程式碼。

像物件一樣對待資料
自動生成的程式碼

在本專欄先前的案例中,有一些就使用了 peewee。比如 Python 高頻詞彙表(關鍵字:單詞)和押韻檢索工具(關鍵字:押韻)。在本公眾號(Crossin的程式設計教室)裡回覆相應關鍵字可檢視文章及程式碼。

最後提一下,除了使用 ORM 外,對於資料儲存還有一種解決方案,就是使用非關係型資料庫,比如 mongodb。儘管坑也不少,但對於簡單的資料儲存來說,它有個巨大的優勢就是同 Python 內建的 dict、list 等型別相容良好,可以直接存取,讓你甚至感覺不到有資料庫的存在,也根本無需關心 SQL 語句。爬蟲實戰課程中的部分案例,就選擇了 mongodb 作為資料儲存方案。

════
其他文章及回答:

如何自學Python | 新手引導 | 精選Python問答 | Python單詞表 | 區塊鏈 | 人工智慧 | 雙11 | 嘻哈 | 爬蟲 | 排序演算法 | 我用Python | 高考 | 世界盃 | requests

歡迎搜尋及關注:Crossin的程式設計教室

像物件一樣對待資料

相關文章