peewee基本操作


本文將簡單的介紹Peewee,一覽它的主要特點,主要涉及到:

  • 模型定義
  • 存儲數據
  • 檢索數據

注意:如果你偏愛稍微高級一點的教程, peewee建立類似twitter應用 是一篇結合Flask框架與peewee的全面教程。

強烈 建議通過SHELL交互的方式執行命令,這種方式可以提高你輸入查詢的快感。

 

模型定義

模型類、字段以及模型實例與數據的對於關系:

peewee 數據庫
Model class Database table
Field instance Column on a table
Model instance Row in a database table

開始一個peewee的項目時,通常最好通過定義一個或多個 Model classes: 來開始你的數據模型。

from peewee import * db = SqliteDatabase('people.db') class Person(Model): name = CharField() birthday = DateField() is_relative = BooleanField() class Meta: database = db # This model uses the "people.db" database. 

Note

注意我們使用 Person 替代了 People 來命名我們的模型,你應該遵循這個約定——即使該表包含多個人,我們總是使用單數的形式來命名模型類。

有許多 field types 適用於存儲各種類型的數據,Peewee可以自動的轉換python中的值到數據庫中使用,所以你不用擔心代碼中Python的類型。

當我們通過使用 外鍵 來創建關聯模型的時候非常有趣,使用peewee將變得非常簡單:

class Pet(Model): owner = ForeignKeyField(Person, related_name='pets') name = CharField() animal_type = CharField() class Meta: database = db # this model uses the "people.db" database 

現在我們有了模型,接下來連接數據庫吧,雖然沒有必要建立顯示連接,這是個好的習慣,一旦發現連接數據發送錯誤,便可以排除之后的查詢錯誤,當處理完畢后應當關閉連接。比如:一個web應用程序當收到請求的時候可能會打開一個連接,響應后將關閉連接。

>>> db.connect() 

然后我們在數據庫中傳接用於存儲我們數據的表,這將創建具有相應列、索引、自增鍵以及外鍵:

>>> db.create_tables([Person, Pet]) 

 

存儲數據

接下來我們用一些人填充數據庫吧,可以使用 save() 與 create() 方法添加和更新人的記錄。

>>> from datetime import date >>> uncle_bob = Person(name='Bob', birthday=date(1960, 1, 15), is_relative=True) >>> uncle_bob.save() # bob is now stored in the database 1 

Note

當你調用 save() 的時候,將返回影響到的行數。

你也可以調用 create() 方法新增一個人,它將返回一個模型實例:

>>> grandma = Person.create(name='Grandma', birthday=date(1935, 3, 1), is_relative=True) >>> herb = Person.create(name='Herb', birthday=date(1950, 5, 5), is_relative=False) 

為了更新一行,可以修改模型實例,調用 save() 來保存更改。這里我們將改變Grandma名字,然后存儲到數據庫:

>>> grandma.name = 'Grandma L.' >>> grandma.save() # Update grandma's name in the database. 1 

現在我們已經在數據庫中保存了3個人了,接下來給他們一些寵物吧。Grandma不喜歡寵物在屋子里亂跑,所以她一只都沒有,但Herb是個寵物達人:

>>> bob_kitty = Pet.create(owner=uncle_bob, name='Kitty', animal_type='cat') >>> herb_fido = Pet.create(owner=herb, name='Fido', animal_type='dog') >>> herb_mittens = Pet.create(owner=herb, name='Mittens', animal_type='cat') >>> herb_mittens_jr = Pet.create(owner=herb, name='Mittens Jr', animal_type='cat') 

在經歷很長的一段生活后,Mittens生病死了,我們需要將它從數據庫中移出:

>>> herb_mittens.delete_instance() # he had a great life 1 

Note

delete_instance() 返回所有影響到的刪除行數。

Bob叔叔考慮到Herb家已經死了許多寵物,決定收養Fido:

>>> herb_fido.owner = uncle_bob >>> herb_fido.save() >>> bob_fido = herb_fido # rename our variable for clarity 

 

檢索數據

數據庫的強大之處在於允許我們通過 查詢 來檢索數據,關系型數據庫針對點對點查詢非常優異。

獲取單條數據

讓我們從數據庫中獲取Grandma的數據,使用 SelectQuery.get() 來從數據庫中獲取單條數據:

>>> grandma = Person.select().where(Person.name == 'Grandma L.').get() 

我們也可以等價簡寫成 Model.get() :

>>> grandma = Person.get(Person.name == 'Grandma L.') 

記錄列表

獲取數據庫中的所有人:

>>> for person in Person.select(): ... print person.name, person.is_relative ... Bob True Grandma L. True Herb False 

獲取數據庫中所有貓以及主人的名字:

>>> query = Pet.select().where(Pet.animal_type == 'cat') >>> for pet in query: ... print pet.name, pet.owner.name ... Kitty Bob Mittens Jr Herb 

上一個查詢是有問題的:因為我們訪問了 pet.owner.name ,但我們並沒有在原始查詢中進行查詢,peewee不得不進行一個額外的查詢來檢索寵物的主人,該行為請參考 N+1 ,通常這應當避免的。

為了避免額外的查詢,我們可以通過添加 join 來同時查詢 Pet 和 Person

>>> query = (Pet ... .select(Pet, Person) ... .join(Person) ... .where(Pet.animal_type == 'cat')) >>> for pet in query: ... print pet.name, pet.owner.name ... Kitty Bob Mittens Jr Herb 

獲取Bob的所有寵物

>>> for pet in Pet.select().join(Person).where(Person.name == 'Bob'): ... print pet.name ... Kitty Fido 

我們還可以做另外一件很酷的事情來獲取Bob的寵物,一旦擁有可以代表Bob的對象,我們可以這樣替代:

>>> for pet in Pet.select().where(Pet.owner == uncle_bob): ... print pet.name 

可以通過 order_by() 語句來排序:

>>> for pet in Pet.select().where(Pet.owner == uncle_bob).order_by(Pet.name): ... print pet.name ... Fido Kitty 

獲取有所人,並且按照年齡從小到大排序:

>>> for person in Person.select().order_by(Person.birthday.desc()): ... print person.name, person.birthday ... Bob 1960-01-15 Herb 1950-05-05 Grandma L. 1935-03-01 

獲取所有人 以及 他們寵物的一些信息:

>>> for person in Person.select(): ... print person.name, person.pets.count(), 'pets' ... for pet in person.pets: ... print ' ', pet.name, pet.animal_type ... Bob 2 pets  Kitty cat  Fido dog Grandma L. 0 pets Herb 1 pets  Mittens Jr cat 

我們再一次運行了典型的 N+1 查詢行為,可以進行 JOIN 操作並且合並起來:

>>> subquery = Pet.select(fn.COUNT(Pet.id)).where(Pet.owner == Person.id) >>> query = (Person ... .select(Person, Pet, subquery.alias('pet_count')) ... .join(Pet, JOIN.LEFT_OUTER) ... .order_by(Person.name)) >>> for person in query.aggregate_rows(): # Note the `aggregate_rows()` call. ... print person.name, person.pet_count, 'pets' ... for pet in person.pets: ... print ' ', pet.name, pet.animal_type ... Bob 2 pets  Kitty cat  Fido dog Grandma L. 0 pets Herb 1 pets  Mittens Jr cat 

甚至我們創建了單獨的子查詢,但只執行了 有且僅有一個 查詢。

最后我們處理一個復雜一點的,獲取所有人,只要他們的生日:

  • 1940之前 (grandma)
  • 1959之后 (bob)
>>> d1940 = date(1940, 1, 1) >>> d1960 = date(1960, 1, 1) >>> query = (Person ... .select() ... .where((Person.birthday < d1940) | (Person.birthday > d1960))) ... >>> for person in query: ... print person.name, person.birthday ... Bob 1960-01-15 Grandma L. 1935-03-01 

現在在做一件相反的事情,獲取1940到1960之間的人:

>>> query = (Person ... .select() ... .where((Person.birthday > d1940) & (Person.birthday < d1960))) ... >>> for person in query: ... print person.name, person.birthday ... Herb 1950-05-05 

最后一次查詢,使用SQL函數來檢索所有名字以 G 開頭的人,不區分大小寫:

>>> expression = (fn.Lower(fn.Substr(Person.name, 1, 1)) == 'g') >>> for person in Person.select().where(expression): ... print person.name ... Grandma L. 

我們已經處理完數據庫,最后關閉連接:

>>> db.close() 

這些都是基礎的使用,你可以進行更加復雜的操作。

所有其他的一些SQL語句也是可用的,比如:

  • group_by()
  • having()
  • limit() 與 offset()

詳情請參考 Querying 文檔。

與現有的數據庫一起工作

如果你已經擁有了數據庫,可以使用 pwiz, a model generator 模型生成器自動生成peewee模型,例如,如果我有一個名為 charles_blog 的postgresql數據庫,我可能會運行:

python -m pwiz -e postgresql charles_blog > blog_models.py


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM