Peewee - 快速指南



Peewee - 概述

Peewee 是一個 Python 物件關係對映 (ORM) 庫,由美國軟體工程師Charles Leifer於 2010 年 10 月開發。其最新版本為3.13.3。Peewee 支援 SQLite、MySQL、PostgreSQL 和 Cockroach 資料庫。

物件關係對映是一種程式設計技術,用於在面向物件程式語言中轉換不相容型別系統之間的資料。

在 Python 等面向物件 (OO) 程式語言中定義的類被認為是非標量的。它不能表示為基本型別,例如整數和字串。

另一方面,像 Oracle、MySQL、SQLite 等資料庫只能儲存和操作標量值,例如組織在表中的整數和字串。

程式設計師必須將物件值轉換為標量資料型別的組以儲存在資料庫中,或者在檢索時將其轉換回來,或者僅在程式中使用簡單的標量值。

在 ORM 系統中,每個類都對映到底層資料庫中的一個表。ORM處理了這些問題,而不是讓您自己編寫乏味的資料庫介面程式碼,而您可以專注於系統邏輯的程式設計。

環境設定

要安裝託管在 PyPI(Python 包索引)上的最新版本的 Peewee,請使用 pip 安裝程式。

pip3 install peewee

Peewee 工作沒有其他依賴項。它與 SQLite 一起使用,無需安裝任何其他軟體包,因為 sqlite3 模組與標準庫捆綁在一起。

但是,要使用 MySQL 和 PostgreSQL,您可能需要分別安裝與 DB-API 相容的驅動程式模組 pymysql 和 pyscopg2。Cockroach 資料庫透過預設與 Peewee 一起安裝的 playhouse 擴充套件進行處理。

Peewee 是一個開源專案,託管在https://github.com/coleifer/peewee 儲存庫中。因此,可以使用 git 從這裡安裝。

git clone https://github.com/coleifer/peewee.git
cd peewee
python setup.py install

Peewee - 資料庫類

Peewee 包中 Database 類的物件表示與資料庫的連線。Peewee 透過 Database 類的相應子類為 SQLite、PostgreSQL 和 MySQL 資料庫提供了開箱即用的支援。

Database 類例項包含開啟與資料庫引擎連線所需的所有資訊,並用於執行查詢、管理事務和執行表的內省、列等。

Database 類具有SqliteDatabasePostgresqlDatabaseMySQLDatabase 子類。雖然 Python 標準庫中包含 sqlite3 模組形式的 SQLite 的 DB-API 驅動程式,但必須首先安裝psycopg2pymysql 模組才能將 PostgreSql 和 MySQL 資料庫與 Peewee 一起使用。

使用 Sqlite 資料庫

Python 以 sqlite3 模組的形式內建支援 SQLite 資料庫。因此,連線非常容易。Peewee 中 SqliteDatabase 類的物件表示連線物件。

con=SqliteDatabase(name, pragmas, timeout)

這裡,pragma 是 SQLite 擴充套件,用於修改 SQLite 庫的操作。此引數可以是字典或包含 pragma 鍵和值的 2 元組列表,每次開啟連線時都會設定。

超時引數以秒為單位指定,以設定 SQLite 驅動程式的繁忙超時。這兩個引數都是可選的。

以下語句使用新的 SQLite 資料庫(如果尚不存在)建立連線。

>>> db = peewee.SqliteDatabase('mydatabase.db')

Pragma 引數通常用於新的資料庫連線。pragmase 字典中提到的典型屬性是journal_modecache_sizelocking_modeforeign-keys 等。

>>> db = peewee.SqliteDatabase(
   'test.db', pragmas={'journal_mode': 'wal', 'cache_size': 10000,'foreign_keys': 1}
)

以下 pragma 設定是理想的指定內容:

Pragma 屬性 推薦值 含義
journal_mode wal 允許讀者和作者共存
cache_size -1 * data_size_kb 以 KiB 為單位設定頁面快取大小
foreign_keys 1 強制執行外部索引鍵約束
ignore_check_constraints 0 強制執行 CHECK 約束
Synchronous 0 讓作業系統處理 fsync

Peewee 還有另一個 Python SQLite 包裝器 (apsw),一個高階 sqlite 驅動程式。它提供了高階功能,例如虛擬表和檔案系統以及共享連線。APSW 比標準庫 sqlite3 模組更快。

Peewee - 模型

Peewee API 中 Model 子類的物件對應於已建立連線的資料庫中的表。它允許在 Model 類中定義的方法的幫助下執行資料庫表操作。

使用者定義的模型具有一到多個類屬性,每個屬性都是 Field 類的物件。Peewee 有許多用於儲存不同型別資料的子類。例如 TextField、DatetimeField 等。它們對應於資料庫表中的欄位或列。關聯資料庫和表的引用以及模型配置在 Meta 類中提及。以下屬性用於指定配置:

Meta 類屬性

Meta 類屬性解釋如下:

序號 屬性和描述
1

資料庫

模型的資料庫。

2

db_table

儲存資料的表名。預設情況下,它是模型類名。

3

索引

要索引的欄位列表。

4

primary_key

複合鍵例項。

5

約束

表約束列表。

6

模式

模型的資料庫模式。

7

臨時

指示臨時表。

8

depends_on

指示此表依賴於另一個表進行建立。

9

without_rowid

指示表不應具有 rowid(僅限 SQLite)。

以下程式碼定義了 mydatabase.db 中 User 表的 Model 類:

from peewee import *
db = SqliteDatabase('mydatabase.db')
class User (Model):
   name=TextField()
   age=IntegerField()
   class Meta:
      database=db
      db_table='User'
User.create_table()

create_table() 方法是 Model 類的類方法,執行等效的 CREATE TABLE 查詢。另一個例項方法save()新增對應於物件的行。

from peewee import *
db = SqliteDatabase('mydatabase.db')
class User (Model):
   name=TextField()
   age=IntegerField()
   class Meta:
      database=db
      db_table='User'

User.create_table()
rec1=User(name="Rajesh", age=21)
rec1.save()

Model 類中的方法

Model 類中的其他方法如下:

序號 Model 類和描述
1

類方法 alias()

為模型類建立別名。它允許在查詢中多次引用同一模型。

2

類方法 select()

執行 SELECT 查詢操作。如果未顯式提供欄位作為引數,則查詢預設將執行等效於 SELECT * 的操作。

3

類方法 update()

執行 UPDATE 查詢函式。

4

類方法 insert()

在對映到模型的底層表中插入新行。

5

類方法 delete()

執行刪除查詢,通常與 where 子句的過濾器相關聯。

6

類方法 get()

從對映表中檢索與給定過濾器匹配的單個行。

7

get_id()

例項方法返回行的主鍵。

8

save()

將物件的資料儲存為新行。如果主鍵值已存在,則會導致執行 UPDATE 查詢。

9

類方法 bind()

將模型繫結到給定的資料庫。

Peewee - 欄位類

Model 類包含一個或多個屬性,這些屬性是 Peewee 中 Field 類的物件。不會直接例項化 Base Field 類。Peewee 為等效的 SQL 資料型別定義了不同的子類。

Field 類的建構函式具有以下引數:

序號 建構函式和描述
1

column_name (str)

指定欄位的列名。

2

primary_key (bool)

欄位是主鍵。

3

constraints (list)

要應用於列的約束列表

4

choices (list)

一個 2 元組的可迭代物件,用於將列值對映到顯示標籤。

5

null (bool)

欄位允許 NULL。

6

index (bool)

在欄位上建立索引。

7

unique (bool)

在欄位上建立唯一索引。

8

預設

預設值。

9

collation (str)

欄位的排序規則名稱。

10

help_text (str)

欄位的幫助文字,用於元資料目的。

11

verbose_name (str)

欄位的詳細名稱,用於元資料目的。

Field 類的子類對映到各個資料庫中對應的資料庫型別,即 SQLite、PostgreSQL、MySQL 等。

數字欄位類

Peewee 中的數字欄位類如下所示:

序號 欄位類和描述
1

IntegerField

用於儲存整數的欄位類。

2

BigIntegerField

用於儲存大整數的欄位類(分別對映到 SQLite、PostgreSQL 和 MySQL 中的 integer、bigint 和 bigint 型別)。

3

SmallIntegerField

用於儲存小整數的欄位類(如果資料庫支援)。

4

FloatField

用於儲存浮點數的欄位類,對應於 real 資料型別。

5

DoubleField

用於儲存雙精度浮點數的欄位類,對映到相應 SQL 資料庫中的等效資料型別。

6

DecimalField

用於儲存十進位制數的欄位類。引數如下所示:

  • max_digits (int) – 儲存的最大位數。

  • decimal_places (int) – 最大精度。

  • auto_round (bool) – 自動舍入值。

文字欄位

Peewee 中可用的文字欄位如下所示:

序號 欄位和描述
1

CharField

用於儲存字串的欄位類。最大 255 個字元。等效的 SQL 資料型別為 varchar。

2

FixedCharField

用於儲存固定長度字串的欄位類。

3

TextField

用於儲存文字的欄位類。對映到 SQLite 和 PostgreSQL 中的 TEXT 資料型別,以及 MySQL 中的 longtext。

二進位制欄位

Peewee 中的二進位制欄位解釋如下:

序號 欄位和描述
1

BlobField

用於儲存二進位制資料的欄位類。

2

BitField

用於在 64 位整數列中儲存選項的欄位類。

3

BigBitField

用於在二進位制大物件 (BLOB) 中儲存任意大小的點陣圖的欄位類。該欄位將根據需要擴充套件底層緩衝區。

4

UUIDField

用於儲存通用唯一識別符號 (UUID) 物件的欄位類。對映到 Postgres 中的 UUID 型別。SQLite 和 MySQL 沒有 UUID 型別,它儲存為 VARCHAR。

日期和時間欄位

Peewee 中的日期和時間欄位如下所示:

序號 欄位和描述
1

DateTimeField

用於儲存 datetime.datetime 物件的欄位類。接受一個特殊引數字串格式,可以使用該格式對日期時間進行編碼。

2

DateField

用於儲存 datetime.date 物件的欄位類。接受一個特殊引數字串格式來編碼日期。

3

TimeField

用於儲存 datetime.time 物件的欄位類。接受一個特殊引數格式來顯示編碼時間。

由於 SQLite 沒有 DateTime 資料型別,因此此欄位對映為字串。

ForeignKeyField

此類用於在兩個模型中建立外部索引鍵關係,因此,在資料庫中建立相應的表。此類使用以下引數例項化:

序號 欄位和描述
1

model (Model)

要引用的模型。如果設定為“self”,則為自引用外部索引鍵。

2

field (Field)

要引用的模型欄位(預設為主鍵)。

3

backref (str)

反向引用的訪問器名稱。“+”停用反向引用訪問器。

4

on_delete (str)

ON DELETE 操作。

5

on_update (str)

ON UPDATE 操作。

6

lazy_load (bool)

訪問外部索引鍵欄位屬性時獲取相關物件。如果為 FALSE,則訪問外部索引鍵欄位將返回儲存在外部索引鍵列中的值。

示例

以下是 ForeignKeyField 的示例。

from peewee import *

db = SqliteDatabase('mydatabase.db')
class Customer(Model):
   id=IntegerField(primary_key=True)
   name = TextField()
   address = TextField()
   phone = IntegerField()
   class Meta:
      database=db
      db_table='Customers'

class Invoice(Model):
   id=IntegerField(primary_key=True)
   invno=IntegerField()
   amount=IntegerField()
   custid=ForeignKeyField(Customer, backref='Invoices')
   class Meta:
      database=db
      db_table='Invoices'

db.create_tables([Customer, Invoice])

執行上述指令碼時,將執行以下 SQL 查詢:

CREATE TABLE Customers (
   id INTEGER NOT NULL
   PRIMARY KEY,
   name TEXT NOT NULL,
   address TEXT NOT NULL,
   phone INTEGER NOT NULL
);
CREATE TABLE Invoices (
   id INTEGER NOT NULL
   PRIMARY KEY,
   invno INTEGER NOT NULL,
   amount INTEGER NOT NULL,
   custid_id INTEGER NOT NULL,
   FOREIGN KEY (
      custid_id
   )
   REFERENCES Customers (id)
);

在 SQLiteStuidio GUI 工具中進行驗證時,表結構如下所示:

ForeignKey Field SQLite Stuidio GUI Tool

其他欄位型別

Peewee 中的其他欄位型別包括:

序號 欄位和描述
1

IPField

用於有效儲存 IPv4 地址(作為整數)的欄位類。

2

BooleanField

用於儲存布林值的欄位類。

3

AutoField

用於儲存自動遞增主鍵的欄位類。

4

IdentityField

用於使用新的 Postgres 10 IDENTITY欄位類儲存自動遞增主鍵的欄位類,使用新的 Postgres 10 IDENTITY 列型別。列型別。

Peewee - 插入新記錄

在 Peewee 中,有多個命令可以向表中新增新記錄。我們已經使用了 Model 例項的 save() 方法。

rec1=User(name="Rajesh", age=21)
rec1.save()

Peewee.Model 類還有一個 create() 方法,該方法建立一個新例項並將它的資料新增到表中。

User.create(name="Kiran", age=19)

此外,Model 還具有 insert() 作為類方法,該方法構造 SQL insert 查詢物件。Query 物件的 execute() 方法執行在底層表中新增一行。

q = User.insert(name='Lata', age=20)
q.execute()

查詢物件是一個等效的 INSERT 查詢。q.sql() 返回查詢字串。

print (q.sql())
('INSERT INTO "User" ("name", "age") VALUES (?, ?)', ['Lata', 20])

以下是演示上述插入記錄方法的完整程式碼。

from peewee import *
db = SqliteDatabase('mydatabase.db')
class User (Model):
   name=TextField()
   age=IntegerField()
   class Meta:
      database=db
      db_table='User'

db.create_tables([User])
rec1=User(name="Rajesh", age=21)
rec1.save()
a=User(name="Amar", age=20)
a.save()
User.create(name="Kiran", age=19)
q = User.insert(name='Lata', age=20)
q.execute()
db.close()

我們可以在 SQLiteStudio GUI 中驗證結果。

SQLite Stuidio GUI

批次插入

為了在表中一次使用多行,Peewee 提供了兩種方法:bulk_create 和 insert_many。

insert_many()

insert_many() 方法使用字典物件的列表生成等效的 INSERT 查詢,每個字典物件都包含一個物件的欄位值對。

rows=[{"name":"Rajesh", "age":21}, {"name":"Amar", "age":20}]
q=User.insert_many(rows)
q.execute()

同樣,q.sql() 返回的 INSERT 查詢字串如下所示:

print (q.sql())
('INSERT INTO "User" ("name", "age") VALUES (?, ?), (?, ?)', ['Rajesh', 21, 'Amar', 20])

bulk_create()

此方法採用一個列表引數,該引數包含一個或多個對映到表的模型的未儲存例項。

a=User(name="Kiran", age=19)
b=User(name='Lata', age=20)
User.bulk_create([a,b])

以下程式碼使用這兩種方法執行批次插入操作。

from peewee import *
db = SqliteDatabase('mydatabase.db')
class User (Model):
   name=TextField()
   age=IntegerField()
   class Meta:
      database=db
      db_table='User'

db.create_tables([User])
rows=[{"name":"Rajesh", "age":21}, {"name":"Amar", "age":20}]
q=User.insert_many(rows)
q.execute()
a=User(name="Kiran", age=19)
b=User(name='Lata', age=20)
User.bulk_create([a,b])
db.close()

Peewee - 選擇記錄

檢索表中資料最簡單和最明顯的方法是呼叫相應模型的 select() 方法。在 select() 方法中,我們可以指定一個或多個欄位屬性。但是,如果未指定任何屬性,則會選擇所有列。

Model.select() 返回一個與行對應的模型例項列表。這類似於 SELECT 查詢返回的結果集,可以透過 for 迴圈遍歷。

from peewee import *
db = SqliteDatabase('mydatabase.db')
class User (Model):
   name=TextField()
   age=IntegerField()
   class Meta:
      database=db
      db_table='User'
rows=User.select()
print (rows.sql())
for row in rows:
   print ("name: {} age: {}".format(row.name, row.age))
db.close()

上述指令碼顯示以下輸出:

('SELECT "t1"."id", "t1"."name", "t1"."age" FROM "User" AS "t1"', [])
name: Rajesh age: 21
name: Amar age  : 20
name: Kiran age : 19
name: Lata age  : 20

Peewee - 過濾器

可以使用 where 子句從 SQLite 表中檢索資料。Peewee 支援以下邏輯運算子列表。

== x 等於 y
< x 小於 y
<= x 小於或等於 y
> x 大於 y
>= x 大於或等於 y
!= x 不等於 y
<< x IN y,其中 y 是列表或查詢
>> x IS y,其中 y 為 None/NULL
% x LIKE y,其中 y 可能包含萬用字元
** x ILIKE y,其中 y 可能包含萬用字元
^ x XOR y
~ 一元否定(例如,NOT x)

以下程式碼顯示年齡>=20的姓名:

rows=User.select().where (User.age>=20)
for row in rows:
   print ("name: {} age: {}".format(row.name, row.age))

以下程式碼僅顯示 names 列表中存在的姓名。

names=['Anil', 'Amar', 'Kiran', 'Bala']
rows=User.select().where (User.name << names)
for row in rows:
   print ("name: {} age: {}".format(row.name, row.age))

因此,Peewee 生成的 SELECT 查詢將為:

('SELECT "t1"."id", "t1"."name", "t1"."age" FROM "User" AS "t1" WHERE 
   ("t1"."name" IN (?, ?, ?, ?))', ['Anil', 'Amar', 'Kiran', 'Bala'])

結果輸出如下所示:

name: Amar age: 20
name: Kiran age: 19

過濾方法

除了上面在核心 Python 中定義的邏輯運算子之外,Peewee 還提供以下方法進行過濾:

序號 方法和描述
1

.in_(value)

IN 查詢(與 << 相同)。
2

.not_in(value)

NOT IN 查詢。

3

.is_null(is_null)

IS NULL 或 IS NOT NULL。接受布林引數。

4

.contains(substr)

子字串的萬用字元搜尋。

5

.startswith(prefix)

搜尋以 prefix 開頭的值。

6

.endswith(suffix)

搜尋以 suffix 結尾的值。

7

.between(low, high)

搜尋介於 low 和 high 之間的值。

8

.regexp(exp)

正則表示式匹配(區分大小寫)。

9

.iregexp(exp)

正則表示式匹配(不區分大小寫)。

10

.bin_and(value)

二進位制 AND。

11

.bin_or(value)

二進位制 OR。

12

.concat(other)

使用 || 連線兩個字串或物件。

13

.distinct()

標記用於 DISTINCT 選擇的列。

14

.collate(collation)

使用給定的排序規則指定列。

15

.cast(type)

將列的值轉換為給定的型別。

例如,請檢視以下程式碼。它檢索以“R”開頭或以“r”結尾的姓名。

rows=User.select().where (User.name.startswith('R') | User.name.endswith('r'))

等效的 SQL SELECT 查詢為

('SELECT "t1"."id", "t1"."name", "t1"."age" FROM "User" AS "t1" WHERE 
   (("t1"."name" LIKE ?) OR ("t1"."name" LIKE ?))', ['R%', '%r'])

替代方案

Python 的內建運算子 in、not in、and、or 等將不起作用。請改用 Peewee 替代方案。

您可以使用:

  • .in_() 和 .not_in() 方法代替 in 和 not in 運算子。

  • & 代替 and。

  • | 代替 or。

  • ~ 代替 not。

  • .is_null() 代替 is。

  • None 或 == None。

Peewee - 主鍵和複合主鍵

建議關係資料庫中的表應該將其中一列應用於主鍵約束。相應地,Peewee Model 類也可以指定將 primary-key 引數設定為 True 的欄位屬性。但是,如果模型類沒有任何主鍵,則 Peewee 會自動建立一個名為“id”的主鍵。請注意,上面定義的 User 模型沒有任何欄位被明確定義為主鍵。因此,我們資料庫中對映的 User 表有一個 id 欄位。

要定義自動遞增整數主鍵,請在模型中使用 AutoField 物件作為其中一個屬性。

class User (Model):
   user_id=AutoField()
   name=TextField()
   age=IntegerField()
   class Meta:
      database=db
      db_table='User'

這將轉換為以下 CREATE TABLE 查詢:

CREATE TABLE User (
   user_id INTEGER NOT NULL
   PRIMARY KEY,
   name TEXT NOT NULL,
   age INTEGER NOT NULL
);

您還可以將任何非整數字段指定為主鍵,方法是將 primary_key 引數設定為 True。假設我們要將某個字母數字值儲存為 user_id。

class User (Model):
   user_id=TextField(primary_key=True)
   name=TextField()
   age=IntegerField()
   class Meta:
      database=db
      db_table='User'

但是,當模型包含非整數字段作為主鍵時,模型例項的 save() 方法不會導致資料庫驅動程式自動生成新 ID,因此我們需要傳遞 force_insert=True 引數。但是,請注意,create() 方法隱式指定了 force_insert 引數。

User.create(user_id='A001',name="Rajesh", age=21)
b=User(user_id='A002',name="Amar", age=20)
b.save(force_insert=True)

save() 方法還會更新表中的現有行,此時,force_insert 主鍵不是必需的,因為具有唯一主鍵的 ID 已經存在。

Peewee 允許定義複合主鍵的功能。CompositeKey 類的物件在 Meta 類中定義為主鍵。在以下示例中,由 User 模型的 name 和 city 欄位組成的複合鍵已分配為複合鍵。

class User (Model):
   name=TextField()
   city=TextField()
   age=IntegerField()
   class Meta:
      database=db
      db_table='User'
      primary_key=CompositeKey('name', 'city')

此模型轉換為以下 CREATE TABLE 查詢。

CREATE TABLE User (
   name TEXT NOT NULL,
   city TEXT NOT NULL,
   age INTEGER NOT NULL,
   PRIMARY KEY (
      name,
      city
   )
);

如果需要,表不應該有主鍵,則在模型的 Meta 類中指定 primary_key=False。

Peewee - 更新現有記錄

可以透過在模型例項上呼叫 save() 方法以及使用 update() 類方法來修改現有資料。

以下示例使用 get() 方法從 User 表中獲取一行,並透過更改 age 欄位的值來更新它。

row=User.get(User.name=="Amar")
print ("name: {} age: {}".format(row.name, row.age))
row.age=25
row.save()

Method 類的 update() 方法生成 UPDATE 查詢。然後呼叫查詢物件的 execute() 方法。

以下示例使用 update() 方法更改 age 列的值大於 20 的行。

qry=User.update({User.age:25}).where(User.age>20)
print (qry.sql())
qry.execute()

update() 方法呈現的 SQL 查詢如下所示:

('UPDATE "User" SET "age" = ? WHERE ("User"."age" > ?)', [25, 20])

Peewee 還具有 bulk_update() 方法,可以幫助在單個查詢操作中更新多個模型例項。該方法需要更新模型物件以及要更新的欄位列表。

以下示例使用新值更新指定行的 age 欄位。

rows=User.select()
rows[0].age=25
rows[2].age=23
User.bulk_update([rows[0], rows[2]], fields=[User.age])

Peewee - 刪除記錄

在模型例項上執行 delete_instance() 方法將從對映的表中刪除相應的行。

obj=User.get(User.name=="Amar")
obj.delete_instance()

另一方面,delete() 是在模型類中定義的類方法,它生成 DELETE 查詢。執行它會有效地從表中刪除行。

db.create_tables([User])
qry=User.delete().where (User.age==25)
qry.execute()

資料庫中的相關表顯示 DELETE 查詢的效果如下所示:

('DELETE FROM "User" WHERE ("User"."age" = ?)', [25])

Peewee - 建立索引

透過使用 Peewee ORM,可以定義一個模型,該模型將建立一個在單個列以及多個列上建立索引的表。

根據 Field 屬性定義,將 unique 約束設定為 True 將在對映的欄位上建立索引。類似地,將 index=True 引數傳遞給欄位建構函式也會在指定的欄位上建立索引。

在以下示例中,MyUser 模型中有兩個欄位,username 欄位的 unique 引數設定為 True,email 欄位的 index=True

class MyUser(Model):
   username = CharField(unique=True)
   email = CharField(index=True)
   class Meta:
      database=db
      db_table='MyUser'

結果,SQLiteStudio 圖形使用者介面 (GUI) 顯示建立的索引如下所示:

SQLiteStudio graphical user interface

要定義多列索引,我們需要在模型類定義內的 Meta 類中新增 indexes 屬性。它是一個 2 元素元組的元組,每個元組表示一個索引定義。在每個 2 元素元組中,第一部分是欄位名稱的元組,第二部分設定為 True 以使其唯一,否則為 False。

我們定義 MyUser 模型,帶有一個兩列唯一索引,如下所示:

class MyUser (Model):
   name=TextField()
   city=TextField()
   age=IntegerField()
   class Meta:
      database=db
      db_table='MyUser'
      indexes=(
         (('name', 'city'), True),
      )

相應地,SQLiteStudio 顯示索引定義如下面的圖所示:

SQLite Studio My User

索引也可以在模型定義之外構建。

您還可以透過手動將 SQL 幫助器語句作為引數提供給 add_index() 方法來建立索引。

MyUser.add_index(SQL('CREATE INDEX idx on MyUser(name);'))

在使用 SQLite 時,尤其需要上述方法。對於 MySQL 和 PostgreSQL,我們可以獲取 Index 物件並將其與 add_index() 方法一起使用。

ind=MyUser.index(MyUser.name)
MyUser.add_index(ind)

Peewee - 約束

約束是對欄位中可以輸入的可能值的限制。其中一種約束是主鍵。當在欄位定義中指定primary_key=True時,每一行只能儲存唯一值——同一欄位的值不能在另一行中重複。

如果一個欄位不是主鍵,它仍然可以被約束為在表中儲存唯一的值。欄位建構函式也有constraints引數。

以下示例對age欄位應用CHECK約束。

class MyUser (Model):
   name=TextField()
   city=TextField()
   age=IntegerField(constraints=[Check('name<10')])
   class Meta:
      database=db
      db_table='MyUser'

這將生成以下資料定義語言 (DDL) 表示式:

CREATE TABLE MyUser (
   id INTEGER NOT NULL
   PRIMARY KEY,
   name TEXT NOT NULL,
   city TEXT NOT NULL,
   age INTEGER NOT NULL
   CHECK (name < 10)
);

因此,如果新行中age<10將導致錯誤。

MyUser.create(name="Rajesh", city="Mumbai",age=9)
peewee.IntegrityError: CHECK constraint failed: MyUser

在欄位定義中,我們還可以使用DEFAULT約束,如下所示的city欄位定義。

city=TextField(constraints=[SQL("DEFAULT 'Mumbai'")])

因此,模型物件可以在有或沒有city的顯式值的情況下構造。如果未使用,city欄位將填充預設值——孟買。

Peewee - 使用 MySQL

如前所述,Peewee透過MySQLDatabase類支援MySQL資料庫。但是,與SQLite資料庫不同,Peewee無法建立MySql資料庫。您需要手動建立它或使用相容DB-API的模組(如pymysql)的功能。

首先,您應該在您的機器上安裝MySQL伺服器。它可以是從https://dev.mysql.com.tw/downloads/installer/.安裝的獨立MySQL伺服器。

您也可以使用捆綁了MySQL的Apache(例如從https://www.apachefriends.org/download.html下載和安裝的XAMPP)。

接下來,我們安裝pymysql模組,這是一個與DB-API相容的Python驅動程式。

pip install pymysql

然後建立一個名為mydatabase的新資料庫。我們將使用XAMPP中提供的phpmyadmin介面。

My Databases

如果您選擇以程式設計方式建立資料庫,請使用以下Python指令碼:

import pymysql

conn = pymysql.connect(host='localhost', user='root', password='')
conn.cursor().execute('CREATE DATABASE mydatabase')
conn.close()

一旦在伺服器上建立了資料庫,我們現在就可以宣告一個模型,從而在其中建立一個對映表。

MySQLDatabase物件需要伺服器憑據,例如主機、埠、使用者名稱和密碼。

from peewee import *
db = MySQLDatabase('mydatabase', host='localhost', port=3306, user='root', password='')
class MyUser (Model):
   name=TextField()
   city=TextField(constraints=[SQL("DEFAULT 'Mumbai'")])
   age=IntegerField()
   class Meta:
      database=db
      db_table='MyUser'
db.connect()
db.create_tables([MyUser])

Phpmyadmin Web介面現在顯示已建立的myuser表。

Php My Admin

Peewee - 使用 PostgreSQL

Peewee也支援PostgreSQL資料庫。它為此目的提供了PostgresqlDatabase類。在本章中,我們將瞭解如何使用Peewee模型連線到Postgres資料庫並在其中建立表。

與MySQL一樣,無法使用Peewee的功能在Postgres伺服器上建立資料庫。必須使用Postgres shell或PgAdmin工具手動建立資料庫。

首先,我們需要安裝Postgres伺服器。對於Windows作業系統,我們可以下載https://get.enterprisedb.com/postgresql/postgresql-13.1-1-windows-x64.exe並安裝。

接下來,使用pip安裝程式安裝Postgres的Python驅動程式——Psycopg2包。

pip install psycopg2

然後啟動伺服器,可以透過PgAdmin工具或psql shell啟動。我們現在可以建立資料庫了。執行以下Python指令碼在Postgres伺服器上建立mydatabase。

import psycopg2

conn = psycopg2.connect(host='localhost', user='postgres', password='postgres')
conn.cursor().execute('CREATE DATABASE mydatabase')
conn.close()

檢查資料庫是否已建立。在psql shell中,可以使用\l命令進行驗證:

List of Databases

要宣告MyUser模型並在上述資料庫中建立同名表,請執行以下Python程式碼:

from peewee import *

db = PostgresqlDatabase('mydatabase', host='localhost', port=5432, user='postgres', password='postgres')
class MyUser (Model):
   name=TextField()
   city=TextField(constraints=[SQL("DEFAULT 'Mumbai'")])
   age=IntegerField()
   class Meta:
      database=db
      db_table='MyUser'

db.connect()
db.create_tables([MyUser])

我們可以驗證表是否已建立。在shell中,連線到mydatabase並獲取其中的表列表。

My Database

要檢查新建立的MyUser資料庫的結構,請在shell中執行以下查詢:

My User Database

Peewee - 動態定義資料庫

如果您的資料庫計劃在執行時發生變化,請使用DatabaseProxy幫助程式更好地控制如何初始化它。DatabaseProxy物件是一個佔位符,可以使用它在執行時選擇資料庫。

在以下示例中,根據應用程式的配置設定選擇合適的資料庫。

from peewee import *
db_proxy = DatabaseProxy() # Create a proxy for our db.

class MyUser (Model):
   name=TextField()
   city=TextField(constraints=[SQL("DEFAULT 'Mumbai'")])
   age=IntegerField()
   class Meta:
      database=db_proxy
      db_table='MyUser'

# Based on configuration, use a different database.
if app.config['TESTING']:
   db = SqliteDatabase(':memory:')
elif app.config['DEBUG']:
   db = SqliteDatabase('mydatabase.db')
else:
   db = PostgresqlDatabase(
      'mydatabase', host='localhost', port=5432, user='postgres', password='postgres'
   )

# Configure our proxy to use the db we specified in config.
db_proxy.initialize(db)
db.connect()
db.create_tables([MyUser])

您還可以使用資料庫類和模型類中宣告的bind()方法在執行時將模型關聯到任何資料庫物件。

以下示例在資料庫類中使用bind()方法。

from peewee import *

class MyUser (Model):
   name=TextField()
   city=TextField(constraints=[SQL("DEFAULT 'Mumbai'")])
   age=IntegerField()

db = MySQLDatabase('mydatabase', host='localhost', port=3306, user='root', password='')
db.connect()
db.bind([MyUser])
db.create_tables([MyUser])

相同的bind()方法也在Model類中定義。

from peewee import *

class MyUser (Model):
   name=TextField()
   city=TextField(constraints=[SQL("DEFAULT 'Mumbai'")])
   age=IntegerField()

db = MySQLDatabase('mydatabase', host='localhost', port=3306, user='root', password='')
db.connect()
MyUser.bind(db)
db.create_tables([MyUser])

Peewee - 連線管理

預設情況下,Database物件建立時autoconnect引數設定為True。相反,要以程式設計方式管理資料庫連線,最初將其設定為False。

db=SqliteDatabase("mydatabase", autoconnect=False)

資料庫類具有connect()方法,該方法建立與伺服器上存在的資料庫的連線。

db.connect()

始終建議在執行完操作後關閉連線。

db.close()

如果您嘗試開啟一個已經開啟的連線,Peewee將引發OperationError

>>> db.connect()
True
>>> db.connect()
Traceback (most recent call last):
   File "<stdin>", line 1, in <module>
   File "c:\peewee\lib\site-packages\peewee.py", line 3031, in connect
      raise OperationalError('Connection already opened.')
peewee.OperationalError: Connection already opened.

要避免此錯誤,請使用reuse_if_open=True作為connect()方法的引數。

>>> db.connect(reuse_if_open=True)
False

對已關閉的連線呼叫close()不會導致錯誤。但是,您可以使用is_closed()方法檢查連線是否已關閉。

>>> if db.is_closed()==True:
   db.connect()

True
>>>

除了在最後顯式呼叫db.close()之外,還可以將資料庫物件用作context_manager

from peewee import *

db = SqliteDatabase('mydatabase.db', autoconnect=False)

class User (Model):
   user_id=TextField(primary_key=True)
   name=TextField()
   age=IntegerField()
   class Meta:
      database=db
      db_table='User'
with db:
   db.connect()
   db.create_tables([User])

Peewee - 關係和連線

Peewee支援實現不同型別的SQL JOIN查詢。它的Model類有一個join()方法,該方法返回一個Join例項。

M1.joint(m2, join_type, on)

連線表將M1模型對映到m2模型,並返回Join類例項。on引數預設為None,是用於連線謂詞的表示式。

連線型別

Peewee支援以下連線型別(預設值為INNER)。

  • JOIN.INNER

  • JOIN.LEFT_OUTER

  • JOIN.RIGHT_OUTER

  • JOIN.FULL

  • JOIN.FULL_OUTER

  • JOIN.CROSS

為了展示join()方法的使用,我們首先宣告以下模型:

db = SqliteDatabase('mydatabase.db')

class BaseModel(Model):
   class Meta:
      database = db

class Item(BaseModel):
   itemname = TextField()
      price = IntegerField()

class Brand(BaseModel):
   brandname = TextField()
      item = ForeignKeyField(Item, backref='brands')

class Bill(BaseModel):
   item = ForeignKeyField(Item, backref='bills')
   brand = ForeignKeyField(Brand, backref='bills')
   qty = DecimalField()

db.create_tables([Item, Brand, Bill])

接下來,我們使用以下測試資料填充這些表:

Item表

Item表如下所示:

Item Table

Brand表

以下是Brand表:

Brand Table

Bill表

Bill表如下所示:

Bill Table

要執行Brand和Item表之間的簡單連線操作,請執行以下程式碼:

qs=Brand.select().join(Item)
for q in qs:
print ("Brand ID:{} Item Name: {} Price: {}".format(q.id, q.brandname, q.item.price))

結果輸出如下所示:

Brand ID:1 Item Name: Dell Price: 25000
Brand ID:2 Item Name: Epson Price: 12000
Brand ID:3 Item Name: HP Price: 25000
Brand ID:4 Item Name: iBall Price: 4000
Brand ID:5 Item Name: Sharp Price: 12000

連線多個表

我們有一個Bill模型,它與item和brand模型具有兩個外部索引鍵關係。要從所有三個表中獲取資料,請使用以下程式碼:

qs=Bill.select().join(Brand).join(Item)
for q in qs:
print ("BillNo:{} Brand:{} Item:{} price:{} Quantity:{}".format(q.id, \
q.brand.brandname, q.item.itemname, q.item.price, q.qty))

根據我們的測試資料,將顯示以下輸出:

BillNo:1 Brand:HP Item:Laptop price:25000 Quantity:5
BillNo:2 Brand:Epson Item:Printer price:12000 Quantity:2
BillNo:3 Brand:iBall Item:Router price:4000 Quantity:5

Peewee - 子查詢

在SQL中,子查詢是另一個查詢的WHERE子句中的嵌入查詢。我們可以將子查詢實現為model.select()作為外部model.select()語句的where屬性內的引數。

為了演示Peewee中子查詢的使用,讓我們使用以下定義的模型:

from peewee import *
db = SqliteDatabase('mydatabase.db')

class BaseModel(Model):
   class Meta:
      database = db

class Contacts(BaseModel):
   RollNo = IntegerField()
   Name = TextField()
   City = TextField()

class Branches(BaseModel):
   RollNo = IntegerField()
   Faculty = TextField()

db.create_tables([Contacts, Branches])

建立表後,將使用以下示例資料填充它們:

Contacts表

Contacts表如下所示:

Data Table Data Table1

為了僅顯示Contact表中註冊為ETC教師的RollNo的姓名和城市,以下程式碼生成一個SELECT查詢,並在其WHERE子句中包含另一個SELECT查詢。

#this query is used as subquery
faculty=Branches.select(Branches.RollNo).where(Branches.Faculty=="ETC")
names=Contacts.select().where (Contacts.RollNo .in_(faculty))

print ("RollNo and City for Faculty='ETC'")
for name in names:
   print ("RollNo:{} City:{}".format(name.RollNo, name.City))

db.close()

以上程式碼將顯示以下結果

RollNo and City for Faculty='ETC'
RollNo:103 City:Indore
RollNo:104 City:Nasik
RollNo:108 City:Delhi
RollNo:110 City:Nasik

Peewee - 排序

可以使用order_by子句以及模型的select()方法從表中選擇記錄。此外,透過將desc()附加到要對其執行排序的欄位屬性,記錄將按降序收集。

示例

以下程式碼按城市名稱升序顯示Contact表中的記錄。

rows=Contacts.select().order_by(Contacts.City)
print ("Contact list in order of city")
for row in rows:
   print ("RollNo:{} Name: {} City:{}".format(row.RollNo,row.Name, row.City))

輸出

這是一個根據城市名稱升序排列的排序列表。

Contact list in order of city
RollNo:107 Name: Beena City:Chennai
RollNo:102 Name: Amar City:Delhi
RollNo:108 Name: John City:Delhi
RollNo:103 Name: Raam City:Indore
RollNo:101 Name: Anil City:Mumbai
RollNo:106 Name: Hema City:Nagpur
RollNo:104 Name: Leena City:Nasik
RollNo:109 Name: Jaya City:Nasik
RollNo:110 Name: Raja City:Nasik
RollNo:105 Name: Keshav City:Pune

示例

以下程式碼按Name欄位降序顯示列表。

rows=Contacts.select().order_by(Contacts.Name.desc())
print ("Contact list in descending order of Name")
for row in rows:
   print ("RollNo:{} Name: {} City:{}".format(row.RollNo,row.Name, row.City))

輸出

輸出如下所示:

Contact list in descending order of Name
RollNo:110 Name: Raja City:Nasik
RollNo:103 Name: Raam City:Indore
RollNo:104 Name: Leena City:Nasik
RollNo:105 Name: Keshav City:Pune
RollNo:108 Name: John City:Delhi
RollNo:109 Name: Jaya City:Nasik
RollNo:106 Name: Hema City:Nagpur
RollNo:107 Name: Beena City:Chennai
RollNo:101 Name: Anil City:Mumbai
RollNo:102 Name: Amar City:Delhi

Peewee - 計數和聚合

我們可以透過附加count()方法來查詢任何SELECT查詢中報告的記錄數。例如,以下語句返回City='Nasik'的Contacts表中的行數。

qry=Contacts.select().where (Contacts.City=='Nasik').count()
print (qry)

示例

SQL在SELECT查詢中具有GROUP BY子句。Peewee以group_by()方法的形式支援它。以下程式碼返回Contacts表中按城市劃分的姓名計數。

from peewee import *

db = SqliteDatabase('mydatabase.db')
class Contacts(BaseModel):
   RollNo = IntegerField()
   Name = TextField()
   City = TextField()
   class Meta:
      database = db

db.create_tables([Contacts])

qry=Contacts.select(Contacts.City, fn.Count(Contacts.City).alias('count')).group_by(Contacts.City)
print (qry.sql())
for q in qry:
   print (q.City, q.count)

Peewee發出的SELECT查詢如下所示:

('SELECT "t1"."City", Count("t1"."City") AS "count" FROM "contacts" AS "t1" GROUP BY "t1"."City"', [])

輸出

根據Contacts表中的示例資料,將顯示以下輸出:

Chennai 1
Delhi   2
Indore  1
Mumbai  1
Nagpur  1
Nasik   3
Pune    1

Peewee - SQL 函式

美國國家標準學會 (ANSI) 結構化查詢語言 (SQL) 標準定義了許多SQL函式。

以下聚合函式在Peewee中很有用。

  • AVG() - 返回平均值。

  • COUNT() - 返回行數。

  • FIRST() - 返回第一個值。

  • LAST() - 返回最後一個值。

  • MAX() - 返回最大值。

  • MIN() - 返回最小值。

  • SUM() - 返回總和。

為了實現這些SQL函式,Peewee有一個SQL幫助函式fn()。在上面的示例中,我們使用它來查詢每個城市的記錄數。

以下示例構建一個使用SUM()函式的SELECT查詢。

使用前面定義的模型中的Bill和Item表,我們將顯示Bill表中輸入的每個專案的數量總和。

Item表

包含資料的Item表如下所示:

Id Item Name Price
1 Laptop 25000
2 Printer 12000
3 Router 4000

Bill表

Bill表如下所示:

Id Item_id Brand_id Quantity
1 1 3 5
2 2 2 2
3 3 4 5
4 2 2 6
5 3 4 3
6 1 3 1

示例

我們在Bill和Item表之間建立一個連線,從Item表中選擇專案名稱,從Bill表中選擇數量總和。

from peewee import *
db = SqliteDatabase('mydatabase.db')

class BaseModel(Model):
   class Meta:
      database = db

class Item(BaseModel):
   itemname = TextField()
   price = IntegerField()

class Brand(BaseModel):
   brandname = TextField()
   item = ForeignKeyField(Item, backref='brands')

class Bill(BaseModel):
   item = ForeignKeyField(Item, backref='bills')
   brand = ForeignKeyField(Brand,      backref='bills')
   qty = DecimalField()

db.create_tables([Item, Brand, Bill])

qs=Bill.select(Item.itemname, fn.SUM(Bill.qty).alias('Sum'))
   .join(Item).group_by(Item.itemname)
print (qs)
for q in qs:
   print ("Item: {} sum: {}".format(q.item.itemname, q.Sum))

db.close()

以上指令碼執行以下SELECT查詢:

SELECT "t1"."itemname", SUM("t2"."qty") AS "Sum" FROM "bill" AS "t2" 
INNER JOIN "item" AS "t1" ON ("t2"."item_id" = "t1"."id") GROUP BY "t1"."itemname"

輸出

因此,輸出如下所示:

Item: Laptop sum: 6
Item: Printer sum: 8
Item: Router sum: 8

Peewee - 獲取行元組/字典

可以迭代結果集而無需建立模型例項。這可以透過使用以下方法來實現:

  • tuples()方法。

  • dicts()方法。

示例

要將SELECT查詢中的欄位資料作為元組集合返回,請使用tuples()方法。

qry=Contacts.select(Contacts.City, fn.Count(Contacts.City).alias('count'))
   .group_by(Contacts.City).tuples()
lst=[]
for q in qry:
   lst.append(q)
print (lst)

輸出

輸出如下所示:

[
   ('Chennai', 1), 
   ('Delhi', 2), 
   ('Indore', 1), 
   ('Mumbai', 1), 
   ('Nagpur', 1), 
   ('Nasik', 3), 
   ('Pune', 1)
]

示例

要獲取字典物件的集合:

qs=Brand.select().join(Item).dicts()
lst=[]
for q in qs:
   lst.append(q)
print (lst)

輸出

輸出如下所示:

[
   {'id': 1, 'brandname': 'Dell', 'item': 1}, 
   {'id': 2, 'brandname': 'Epson', 'item': 2}, 
   {'id': 3, 'brandname': 'HP', 'item': 1}, 
   {'id': 4, 'brandname': 'iBall', 'item': 3},
   {'id': 5, 'brandname': 'Sharp', 'item': 2}
]

Peewee - 使用者自定義運算子

Peewee有一個Expression類,藉助它,我們可以在Peewee的運算子列表中新增任何自定義運算子。Expression的建構函式需要三個引數,左運算元、運算子和右運算元。

op=Expression(left, operator, right)

使用Expression類,我們定義了一個mod()函式,它接受左運算元和右運算元以及'%'作為運算子的引數。

from peewee import Expression # the building block for expressions

def mod(lhs, rhs):
   return Expression(lhs, '%', rhs)

示例

我們可以在SELECT查詢中使用它來獲取Contacts表中id為偶數的記錄列表。

from peewee import *
db = SqliteDatabase('mydatabase.db')

class BaseModel(Model):
   class Meta:
      database = db

class Contacts(BaseModel):
   RollNo = IntegerField()
   Name = TextField()
   City = TextField()

db.create_tables([Contacts])

from peewee import Expression # the building block for expressions

def mod(lhs, rhs):
   return Expression(lhs,'%', rhs)
qry=Contacts.select().where (mod(Contacts.id,2)==0)
print (qry.sql())
for q in qry:
   print (q.id, q.Name, q.City)

此程式碼將發出以下由字串表示的SQL查詢:

('SELECT "t1"."id", "t1"."RollNo", "t1"."Name", "t1"."City" FROM "contacts" AS "t1" WHERE (("t1"."id" % ?) = ?)', [2, 0])

輸出

因此,輸出如下所示:

2  Amar Delhi
4  Leena Nasik
6  Hema Nagpur
8  John Delhi
10 Raja Nasik

Peewee - 原子事務

Peewee的資料庫類具有atomic()方法,該方法建立一個上下文管理器。它啟動一個新的事務。在上下文塊內,可以根據事務是否已成功完成或遇到異常來提交或回滾事務。

with db.atomic() as transaction:
   try:
      User.create(name='Amar', age=20)
      transaction.commit()
   except DatabaseError:
      transaction.rollback()

atomic()也可以用作裝飾器。

@db.atomic()
def create_user(nm,n):
   return User.create(name=nm, age=n)

create_user('Amar', 20)

多個原子事務塊也可以巢狀。

with db.atomic() as txn1:
   User.create('name'='Amar', age=20)

   with db.atomic() as txn2:
      User.get(name='Amar')

Peewee - 資料庫錯誤

Python的DB-API標準(PEP 249推薦)指定了任何符合DB-API的模組(例如pymysql、pyscopg2等)要定義的異常類型別。

Peewee API為這些異常提供了易於使用的包裝器。PeeweeException是基類,以下異常類已在Peewee API中定義:

  • DatabaseError

  • DataError

  • IntegrityError

  • InterfaceError

  • InternalError

  • NotSupportedError

  • OperationalError

  • 程式設計錯誤

我們可以使用Peewee提供的異常,而不是嘗試使用特定於DB-API的異常。

Peewee - 查詢構建器

Peewee還提供了一個非ORM API來訪問資料庫。我們可以將資料庫表和列繫結到Peewee中定義的TableColumn物件,而不是定義模型和欄位,並透過它們執行查詢。

首先,宣告一個與資料庫中表對應的Table物件。您必須指定表名和列列表。可選地,還可以提供主鍵。

Contacts=Table('Contacts', ('id', 'RollNo', 'Name', 'City'))

此表物件使用bind()方法繫結到資料庫。

Contacts=Contacts.bind(db)

示例

現在,我們可以使用select()方法在此表物件上設定一個SELECT查詢,並如下迭代結果集:

names=Contacts.select()
for name in names:
   print (name)

輸出

預設情況下,行以字典的形式返回。

{'id': 1,  'RollNo': 101, 'Name': 'Anil', 'City': 'Mumbai'}
{'id': 2,  'RollNo': 102, 'Name': 'Amar', 'City': 'Delhi'}
{'id': 3,  'RollNo': 103, 'Name': 'Raam', 'City': 'Indore'}
{'id': 4,  'RollNo': 104, 'Name': 'Leena', 'City': 'Nasik'}
{'id': 5,  'RollNo': 105, 'Name': 'Keshav', 'City': 'Pune'}
{'id': 6,  'RollNo': 106, 'Name': 'Hema', 'City': 'Nagpur'}
{'id': 7,  'RollNo': 107, 'Name': 'Beena', 'City': 'Chennai'}
{'id': 8,  'RollNo': 108, 'Name': 'John', 'City': 'Delhi'}
{'id': 9,  'RollNo': 109, 'Name': 'Jaya', 'City': 'Nasik'}
{'id': 10, 'RollNo': 110, 'Name': 'Raja', 'City': 'Nasik'}

如果需要,可以將其作為元組、命名元組或物件獲取。

元組

程式如下所示:

示例

names=Contacts.select().tuples()
for name in names:
   print (name)

輸出

輸出如下所示:

(1, 101, 'Anil', 'Mumbai')
(2, 102, 'Amar', 'Delhi')
(3, 103, 'Raam', 'Indore')
(4, 104, 'Leena', 'Nasik')
(5, 105, 'Keshav', 'Pune')
(6, 106, 'Hema', 'Nagpur')
(7, 107, 'Beena', 'Chennai')
(8, 108, 'John', 'Delhi')
(9, 109, 'Jaya', 'Nasik')
(10, 110, 'Raja', 'Nasik')

命名元組

程式如下所示:

示例

names=Contacts.select().namedtuples()
for name in names:
   print (name)

輸出

輸出如下所示:

Row(id=1, RollNo=101, Name='Anil', City='Mumbai')
Row(id=2, RollNo=102, Name='Amar', City='Delhi')
Row(id=3, RollNo=103, Name='Raam', City='Indore')
Row(id=4, RollNo=104, Name='Leena', City='Nasik')
Row(id=5, RollNo=105, Name='Keshav', City='Pune')
Row(id=6, RollNo=106, Name='Hema', City='Nagpur')
Row(id=7, RollNo=107, Name='Beena', City='Chennai')
Row(id=8, RollNo=108, Name='John', City='Delhi')
Row(id=9, RollNo=109, Name='Jaya', City='Nasik')
Row(id=10, RollNo=110, Name='Raja', City='Nasik')

要插入新記錄,INSERT查詢構造如下:

id = Contacts.insert(RollNo=111, Name='Abdul', City='Surat').execute()

如果要新增的記錄列表儲存為字典列表或元組列表,則可以批次新增它們。

Records=[{‘RollNo’:112, ‘Name’:’Ajay’, ‘City’:’Mysore’}, 
   {‘RollNo’:113, ‘Name’:’Majid’,’City’:’Delhi’}}

Or

Records=[(112, ‘Ajay’,’Mysore’), (113, ‘Majid’, ‘Delhi’)}

INSERT查詢如下所示:

Contacts.insert(Records).execute()

Peewee的Table物件具有update()方法來實現SQL UPDATE查詢。要更改所有來自Nasik到Nagar的記錄的City,我們使用以下查詢。

Contacts.update(City='Nagar').where((Contacts.City=='Nasik')).execute()

最後,Peewee中的Table類還具有delete()方法來實現SQL中的DELETE查詢。

Contacts.delete().where(Contacts.Name=='Abdul').execute()

Peewee - 與 Web 框架整合

Peewee可以與大多數Python Web框架API無縫協作。每當Web伺服器閘道器介面(WSGI)伺服器從客戶端接收連線請求時,都會建立與資料庫的連線,然後在傳遞響應後關閉連線。

在基於Flask的Web應用程式中使用時,連線會影響@app.before_request裝飾器,並在@app.teardown_request上斷開連線。

from flask import Flask
from peewee import *

db = SqliteDatabase('mydatabase.db')
app = Flask(__name__)

@app.before_request
def _db_connect():
   db.connect()

@app.teardown_request
def _db_close(exc):
   if not db.is_closed():
      db.close()

Peewee API也可以在Django中使用。為此,在Django應用程式中新增一箇中間件。

def PeeweeConnectionMiddleware(get_response):
   def middleware(request):
      db.connect()
      try:
         response = get_response(request)
      finally:
         if not db.is_closed():
            db.close()
      return response
   return middleware

中介軟體新增到Django的settings模組中。

# settings.py
MIDDLEWARE_CLASSES = (
   # Our custom middleware appears first in the list.
   'my_blog.middleware.PeeweeConnectionMiddleware',
   #followed by default middleware list.
   ..
)

Peewee可以方便地與其他框架(如Bottle、Pyramid和Tornado等)一起使用。

Peewee - SQLite 擴充套件

Peewee帶有一個Playhouse名稱空間。它是一組各種擴充套件模組的集合。其中之一是playhouse.sqlite_ext模組。它主要定義了SqliteExtDatabase類,該類繼承了SqliteDatabase類,支援以下附加功能:

SQLite擴充套件的功能

Peewee支援的SQLite擴充套件功能如下:

  • 全文搜尋。

  • JavaScript物件表示法(JSON)擴充套件整合。

  • 閉包表擴充套件支援。

  • LSM1擴充套件支援。

  • 使用者定義的表函式。

  • 支援使用備份API:backup_to_file()進行線上備份。

  • BLOB API支援,用於高效的二進位制資料儲存。

如果將特殊的JSONField宣告為欄位屬性之一,則可以儲存JSON資料。

class MyModel(Model):
   json_data = JSONField(json_dumps=my_json_dumps)

要啟用全文搜尋,模型可以具有DocIdField來定義主鍵。

class NoteIndex(FTSModel):
   docid = DocIDField()
   content = SearchField()

   class Meta:
      database = db

FTSModel是VirtualModel的子類,可在http://docs.peewee-orm.com/en/latest/peewee/sqlite_ext.html#VirtualModel中使用,用於FTS3和FTS4全文搜尋擴充套件。Sqlite會將所有列型別視為TEXT(儘管您可以儲存其他資料型別,Sqlite會將其視為文字)。

SearchField是一個欄位類,用於表示全文搜尋虛擬表的模型上的列。

SqliteDatabase支援AutoField來增加主鍵。但是,SqliteExtDatabase支援AutoIncrementField以確保主鍵始終單調遞增,而不管行是否被刪除。

playhouse名稱空間(playhouse.sqliteq)中的SqliteQ模組定義了SqliteExeDatabase的子類,以處理對SQlite資料庫的序列化併發寫入。

另一方面,playhouse.apsw模組支援apsw sqlite驅動程式。另一個Python SQLite包裝器(APSW)速度很快,並且可以處理巢狀事務,這些事務由您的程式碼顯式管理。

from apsw_ext import *
db = APSWDatabase('testdb')

class BaseModel(Model):
   class Meta:
      database = db

class MyModel(BaseModel):
   field1 = CharField()
   field2 = DateTimeField()

Peewee - PostgreSQL和MySQL擴充套件

playhouse.postgres_ext模組中定義的幫助程式啟用了其他PostgreSQL功能。此模組定義了PostgresqlExtDatabase類,並提供了以下其他欄位型別,這些型別專門用於宣告要對映到PostgreSQL資料庫表的模型。

PostgreSQL擴充套件的功能

Peewee支援的PostgreSQL擴充套件功能如下:

  • ArrayField欄位型別,用於儲存陣列。

  • HStoreField欄位型別,用於儲存鍵值對。

  • IntervalField欄位型別,用於儲存timedelta物件。

  • JSONField欄位型別,用於儲存JSON資料。

  • BinaryJSONField欄位型別用於jsonb JSON資料型別。

  • TSVectorField欄位型別,用於儲存全文搜尋資料。

  • DateTimeTZField欄位型別,一個時區感知的日期時間欄位。

此模組中的其他特定於Postgres的功能旨在提供。

  • hstore支援。

  • 伺服器端遊標。

  • 全文搜尋。

Postgres hstore是一個鍵值儲存,可以作為HStoreField型別欄位之一嵌入到表中。要啟用hstore支援,請使用register_hstore=True引數建立資料庫例項。

db = PostgresqlExtDatabase('mydatabase', register_hstore=True)

使用一個HStoreField定義一個模型。

class Vehicles(BaseExtModel):
   type = CharField()
   features = HStoreField()

如下建立模型例項:

v=Vechicle.create(type='Car', specs:{'mfg':'Maruti', 'Fuel':'Petrol', 'model':'Alto'})

訪問hstore值:

obj=Vehicle.get(Vehicle.id=v.id)
print (obj.features)

MySQL擴充套件

playhouse.mysql_ext模組中定義的MySQLConnectorDatabase提供了MysqlDatabase類的替代實現。它使用Python的DB-API相容的官方mysql/python connector

from playhouse.mysql_ext import MySQLConnectorDatabase

db = MySQLConnectorDatabase('mydatabase', host='localhost', user='root', password='')

Peewee - 使用 CockroachDB

CockroachDB或Cockroach資料庫(CRDB)由計算機軟體公司Cockroach Labs開發。它是一個可擴充套件的、一致複製的事務性資料儲存,旨在將資料的副本儲存在多個位置,以提供快速的訪問。

Peewee透過playhouse.cockroachdb擴充套件模組中定義的CockroachDatabase類為該資料庫提供支援。該模組包含CockroachDatabase的定義,它是核心模組中PostgresqlDatabase類的子類。

此外,還有一個run_transaction()方法,它在事務內執行一個函式,並提供自動的客戶端端重試邏輯。

欄位類

該擴充套件還具有一些特殊的欄位類,用作與CRDB相容的模型中的屬性。

  • UUIDKeyField - 一個主鍵欄位,使用CRDB的UUID型別以及預設的隨機生成的UUID。

  • RowIDField - 一個主鍵欄位,使用CRDB的INT型別以及預設的unique_rowid()。

  • JSONField - 與Postgres BinaryJSONField相同。

  • ArrayField - 與Postgres擴充套件相同,但不支援多維陣列。

廣告

© . All rights reserved.