API 索引
模型
class Model(**kwargs)
模型提供對表的一對一的映射。Model的子類聲明任意多的Field實例當作class屬性。這些字段對應表上的列。
表層次的操作,例如select(),update(),insert(),and delete(),實現類方法。行層次的的操作比如
save(),delete_instance()實現為實例方法。
參數:kwargs-實例模型,給定的鍵值對賦值給相應的字段。
Example:
class User(Model): username = CharField() join_date = DateTimeField(default=datetime.datetime.now) is_admin = BooleanField() u = User(username='charlie', is_admin=True)
classmethod select(*selection)
參數:
- selection-模型類,字段實例,函數或表達式的列表。如果參數沒有提供,給定模型的所有列將被選擇
- 返回類型:給定模型的SelectQuey
選擇所有列的例子:
選擇所有Tweet和關聯模型的所有列 。當user外鍵通過Tweet實例獲取時,沒有第二次查詢:
(Tweet
.select(Tweet, User)
.join(User)
.order_by(Tweet.created_date.desc()))
classmethod update(*update)
參數:
- update -字段名稱到表達式的映射
- 返回類型:UpdateQuery
顯示注冊過期的用戶然后標定為非活躍用戶:
q = User.update(active=False).where(User.registration_expired == True) q.execute() # Execute the query, updating the database.
原子性更新的例子:
q = PageView.update(count=PageView.count + 1).where(PageView.url == url) q.execute() # execute the query, updating the database.
更新查詢執行時,修改行的數量返回
classmethod insert(**insert)
插入新行。如果字段有默認值,在insert參數字典里沒有顯式設置的字段使用這些默認值。
參數:
- insert-field或者字段名稱到表達式的映射
- 返回類型:InsertQuery
創建新用戶的例子:
q = User.insert(username='admin', active=True, registration_expired=False) q.execute() # perform the insert.
你也可以使用Field對象作為鍵:
User.insert(**{User.username: 'admin'}).execute()
如果你有一個擁有字段默認值的模型,如果插入參數沒有指名它,默認值將被使用:
class User(Model): username = CharField() active = BooleanField(default=True) # This INSERT query will automatically specify `active=True`: User.insert(username='charlie')
當插入查詢在有自增主鍵的表上執行時,新行的主鍵將返回。
insert_many(rows)
一次插入多行。rows參數必須是一個字典的可迭代對象,和insert相同,字典中沒有聲明的字段使用默認值。
由於批量插入的原生性,每行應該有相同字段。下面的例子不行:
Person.insert_many([ {'first_name': 'Peewee', 'last_name': 'Herman'}, {'first_name': 'Huey'}, # Missing "last_name"! ])
- 參數:rows -包含鍵值對的可迭代對象
- 返回類型:InsertQuery
使用批量插入的例子:
usernames = ['charlie', 'huey', 'peewee', 'mickey'] row_dicts = ({'username': username} for username in usernames) # Insert 4 new rows. User.insert_many(row_dicts).execute()
因為rows參數可以為任意的迭代對象,你也可以使用生成器:
def get_usernames(): for username in ['charlie', 'huey', 'peewee']: yield {'username': username} User.insert_many(get_usernames()).execute()
classmethod insert_from(fields,query)
使用查詢作為數據源插入數據。該API使用INSERT INTO ...SELECT FROM 查詢。
參數:
- fields-將選擇的數據映射到字段對象
- query-新行的查詢
返回類型:InsertQuery
非正常的跨表插入數據:
source = (User
.select(User.username, fn.COUNT(Tweet.id))
.join(Tweet, JOIN.LEFT_OUTER)
.group_by(User.username))
UserTweetDenorm.insert_from(
[UserTweetDenorm.username, UserTweetDenorm.num_tweets],
source).execute()
classmethod delete()
返回類型:DeleteQuery
刪除非活躍用戶的例子:
q = User.delete().where(User.active == False) q.execute() # remove the rows
這個方法在整表上刪除,刪除一個實例使用Model.delete_instance()
classmethod raw(sql,*params)
參數:sql -SQL表達式
參數-操作時插入的參數
選擇所有用戶例子:
q = User.raw('select id, username from users') for user in q: print user.id, user.username
raw作為保留使用,是為了顯著優化查詢的場景使用。因為它返回模型的實例所以select插詢很有用。
classmethod create(**attrubutes)
參數:
- attributes-模型屬性的鍵值對
返回類型 擁有提供屬性的模型實例
用戶創建的例子(新行增加到數據庫):
user = User.create(username='admin', password='test')
create方法是實例化對象然后保存的簡單快捷方式
classmethod get(*args)
- 參數:args-插詢表達式的列表
- 返回類型:Model實例或者DoesNotExist錯誤
得到匹配的單行。若沒有行返回,則拋出錯誤DoesNotExist
user = User.get(User.username == username, User.active == True)
這個方法在SelectQuery上也可以使用,雖然沒有接受參數:
active = User.select().where(User.active == True) try: user = active.where( (User.username == username) & (User.active == True) ).get() except User.DoesNotExist: user = None
get方法是選擇單一記錄的簡單方式。當沒有記錄匹配加上拋出錯誤行為。如果多行返回,數據庫游標的首行返回。
classsmethod get_or_create([deaults=None[,**kwargs]])
- 參數:defaults-在新增對象實例上的默認值,是一個字典
- kwargs:Diango風格的過濾器指名get的模型,以及賦給新實例的屬性值
返回值: 一個二元元組包含模型實例和boolean值標明是否對象是創建的。
這個函數試圖根據提供的過濾器取得模型實例。如果沒有匹配的結果,新模型根據默認值和過濾器中的參數被創建。
當調用get_or_create 加上autocommit=False時小心,因為這個方法調用Database.atomic()來創建對象,而不是使用事務或保存節點。
沒有使用get_or_create的例子:
# Without `get_or_create`, we might write: try: person = Person.get( (Person.first_name == 'John') & (Person.last_name == 'Lennon')) except Person.DoesNotExist: person = Person.create( first_name='John', last_name='Lennon', birthday=datetime.date(1940, 10, 9))
等效於使用get_or_create:
person, created = Person.get_or_create( first_name='John', last_name='Lennon', defaults={'birthday': datetime.date(1940, 10, 9)})
classmethod create_or_get([**kwargs])
參數:kwargs-字段名稱和值來嘗試創建新對象。
返回值:一個二元元組包含一個對象實例以及Boolean值標明對象是否被創建
這個函數試圖創建對象實例根據提供的關鍵字參數。如果IntegrityError發生,標明約束沖突,Peewee返回匹配過濾器的模型。
Peewee將不嘗試匹配所有的關鍵字參數來遇到IntegrityError發生。只有主鍵的字段或者擁有唯一約束的字段來取到對象實例。
當使用autocommit=False來create_or_get時小心,因為這個方法將調用Database.atomic()來創建對象,而不是事務或保存節點。
例子:
# This will succeed, there is no user named 'charlie' currently. charlie, created = User.create_or_get(username='charlie') # This will return the above object, since an IntegrityError occurs # when trying to create an object using "charlie's" primary key. user2, created = User.create_or_get(username='foo', id=charlie.id) assert user2.username == 'charlie'
classmethod alias()
返回類型 ModelAlias實例
alias方法來創建自關聯查詢:
例子:
Parent = Category.alias() sq = (Category .select(Category, Parent) .join(Parent, on=(Category.parent == Parent.id)) .where(Parent.name == 'parent category'))
當使用ModelAlias時,你必須顯示聲明關聯條件。
classmethod create_table([fail_silently=False])
參數:fail_silently(Boolean)-設置為True,將檢查表名是否已存在。
創建根據模型的表,同樣創建模型中定義的約束和索引:
例子:
database.connect() SomeModel.create_table() # Execute the create table query.
classmethod drop_table([fair_silently=False,[,cascase=False]])
參數:fail_silently(Boolean)將檢查表是否存在
cascade-CASCADE選項情況下刪除表
刪除模型對應的表
classmethod table_exists()
返回類型:標明模型對應的表是否數據庫中已經存在
classmethod sqlall()
返回值:返回需要創建表和索引的一系列查詢
save([force_insert=False,[,only=None]])
參數:
- force_insert(bool)-是否強制插入
- only(list)-需要持久化的字段-當提供此參數時,只有提供的字段被持久化。
保存給定的實例,當創建或者更新根據它是否有主鍵。如果force_insert=True INSERT將忽略是否主鍵存在而執行插入。
保存模型實例的例子:
user = User() user.username = 'some-user' # does not touch the database user.save() # change is persisted to the db
delete_instance([recursive=False,[,delete_nullable=False]])
參數:
- recursive-刪除實例和依賴它的別的實例,選擇性參數更新那些nullable的依賴
- delete_nullable-如果遞歸刪除,不論依賴的對象是否可以被更新為NULL,都刪除它們
刪除給定的實例。任何已刪除對象為外鍵的對象也被自動刪除。更詳細的程序控制,你可以用recursive=True,任何相關聯的non-nullable模型也被刪除(相關聯的nullable設置為NULL)。
如果你想要同時刪除nullable模型,設置delete_nullable=True。
例子:
some_obj.delete_instance() # it is gone forever
dependencies([search_nullable=False])
參數:
search_nullable(bool)-通過nullable外鍵搜索關聯的模型
返回類型:生成查詢和外鍵字段的生成器表達式
生成依賴模型的查詢列表。生成二元元組,其包含查詢餓相關聯的外鍵字段。對於查詢模型的依賴有用,例如當刪除事件發生時,需要做些別的操作。
dirty_fields
返回手動設置的字段列表
返回類型:list
如果你只是想要持久化修改的字段,你可以調用model.save(only=model.dirty_fields)
如果你想要只是保存模型的dirty_fields,你可以用Meta設置only_save_dirty=True。這樣,每次你調用Model.save(),默認只是dirty fields才會保存:
class Person(Model): first_name = CharField() last_name = CharField() dob = DateField() class Meta: database = db only_save_dirty = True
is_dirty()
返回是否任何字段已經手動修改
返回類型:bool
prepared()
這個方法提供了鈎子,行數據生成后執行模型初始化
Fields
Field(null=False,index=False,unique=False,verbose_name=None,help_text=None, db_column=None, default=None, choices=None, primary_key=False, sequence=None, constraints=None, schema=None, **kwargs)
參數:
- null(bool)- 是否這個列接受None或者NULL值
- index(bool)-是否在這個列創建索引
- unique(bool)-是否在此列上創建唯一索引
- verbose_name(string)-表示這個字段的verbose名字,元數據目的有用
- help_text(string)-表示這個字段的幫助描述文字
- db_column(string)-存儲時映射到的字段名字,對與數據庫兼容性有用.
- default-未初始化是的默認值
- choices-一個二元數組的可迭代對象,映射值本身到顯示的值
- primary_key(bool)-是否為表的主鍵
- sequence(string)-序列的名字(如果向后數據庫支持)
- constraints(list)約束的數組例如[check('price>0')]
- schema(string)-schema的名字(如果向后數據庫支持)
- kwargs-包含可能用來標明特殊字段子類型的命名屬性,比如"max_length或者decimal_places"
db_field='<some field type'>'
映射這個字段到的列類型,例如:string或者DateTimeField
_is_bound
標明這個字段綁定到模型類的Boolean標志
model_class
對應的模型類.只在綁定的字段上有用
name
字段的名稱.只在綁定的字段上有用
db_value(value)
參數:value-對應數據庫存儲的python數據類型
返回類型:python數據類型轉換以后的數據庫類型
python_value(value)
參數:value-從后端存儲的數據
返回類型:python數據類型
coerce(value)
用於db_value和python_value的快捷方法.你可以盡管實現
參數:value-app或者數據庫任意的類型
返回類型:python數據類型
class IntegerField
存儲:integers
db_field = 'int'
class BigIntegerField
存儲:大整型數
db_field = 'bigint'
class PrimaryKeyField
存儲:作為主鍵的合適的自增整型字段
db_field = 'primary_key'
class FloatField
存儲:浮點數字
db_field = 'float'
class DoubleField
存儲:雙精度浮點數字
db_field = 'double'
class DecimalField
存儲:數字,使用python標准庫中的Decimal對象
額外的屬性和值:
max_digits |
10 |
decimal_places |
5 |
auto_round |
False |
rounding |
decimal.DefaultContext.rounding |
db_field = 'decimal'
class CharField
存儲:小的字符串(0-255字節)
額外的熟悉和值:
max_length |
255 |
db_field = 'string'
class TextField
存儲:任意大字符串
db_field = 'text'
class DateTimeField
存儲:python datetime.datetime實例
接收特殊的參數formats,包含時間格式列表。默認的格式是:
'%Y-%m-%d %H:%M:%S.%f' # year-month-day hour-minute-second.microsecond '%Y-%m-%d %H:%M:%S' # year-month-day hour-minute-second '%Y-%m-%d' # year-month-day
注意
如果拿來的值不匹配格式,它將返回原來的樣子
db_field='datetime'
year
提取年份的表達式,例如:查詢2013年以來的所有博客:
Blog.select().where(Blog.pub_date.year == 2013)
month
從存儲的日期里提取月。
day
從存儲日期里提取天。
hour
從存儲日期里提取小時
minute
從存儲日期里提取分鍾
second
從存儲日期里提取秒
class DateField
存儲:python datetime.date實例
接受參數formats,包含格式日期的格式列表。默認格式是:
'%Y-%m-%d' # year-month-day '%Y-%m-%d %H:%M:%S' # year-month-day hour-minute-second '%Y-%m-%d %H:%M:%S.%f' # year-month-day hour-minute-second.microsecond
注意:
如果來的值不匹配一個格式,返回原來的樣子
db_field='date'
year
從日期里提取年的表達式,例如取得1980年出生的人:
Person.select().where(Person.dob.year == 1983)
month
提取月
day
提取天
class TimeField
存儲:python datetime.time實例
接受formats參數,包含格式列表。默認值有:
'%H:%M:%S.%f' # hour:minute:second.microsecond '%H:%M:%S' # hour:minute:second '%H:%M' # hour:minute '%Y-%m-%d %H:%M:%S.%f' # year-month-day hour-minute-second.microsecond '%Y-%m-%d %H:%M:%S' # year-month-day hour-minute-second
注意:
如果來的值沒有匹配的格式,返回原值
db_field=‘time'
hour
從時間里提取小時.例如得到發生在晚上的事件:
Event.select().where(Event.time.hour > 17)
minute
提取分鍾
second
提取秒
class BooleanField
存儲:True/False
db_field='bool'
class BlobField
存儲任意的二進制數據
class UUIDField
存儲UUID值
注意:
此字段只支持PostgresqlDatabase.
class BareField
在SQLite中使用.因為數據類型不強制,你可以聲明沒有任何數據類型的字段.對於SQLite虛擬表來說使用元列和未名類型列來說很普遍,所以你可使用未名類型字段.
接受coerce參數,一個函數,用來將數據庫類型和Python數據類型相互轉換.
注意:
當前此字段只支持SQLiteDatabase
class ForeignKeyField(rel_model,[ralated_name=None[,on_delete=None[,on_update=None,[,to_field=None[,..]]]]])
存儲:到另一個模型的關系
參數:
- rel_model-關聯的Model類或者self字符來表示自引用的外鍵
- related_name(string)-對應關聯模型的屬性
- on_delete(string)-當刪除時的行為,例如:on_delete='CASCADE'
on_update(string)-當更新時的行為
to_field-rel_model外鍵引用的字段.默認主鍵字段當作rel_model
class User(Model): name = CharField() class Tweet(Model): user = ForeignKeyField(User, related_name='tweets') content = TextField() # "user" attribute >>> some_tweet.user <User: charlie> # "tweets" related name attribute >>> for tweet in charlie.tweets: ... print tweet.content Some tweet Another tweet Yet another tweet
外鍵沒有特殊的db_field因為他們的字段類型取決於他們關聯的模型主鍵的字段類型
如果你手動的標示to_field,這個字段必須是主鍵或者有唯一約束
class CompositeKey(*fields)
表示模型的復合主鍵.不像其它字段,復合主鍵在所有字段定義完成后定義在Meta 類中.它接受用作主鍵的字段名字的字符列表作參數:
class BlogTagThrough(Model): blog = ForeignKeyField(Blog, related_name='tags') tag = ForeignKeyField(Tag, related_name='blogs') class Meta: primary_key = CompositeKey('blog', 'tag')
Query Types
class Query
是所有其它查詢類的父類.你可能不直接在你的代碼里處理Query,所有的查詢類型實現了一些方法.
where(*expressions)
參數:表達式-一個或多個表達式
返回類型:查詢實例
選擇用戶名為somebody的用戶:
sq = SelectQuery(User).where(User.username == 'somebody')
選擇編輯和管理員的tweets
sq = SelectQuery(Tweet).join(User).where( (User.is_editor == True) | (User.is_admin == True))
刪除不活躍用戶的tweets:
dq = DeleteQuery(Tweet).where( Tweet.user << User.select().where(User.active == False)) dq.execute() # perform the delete query
where調用是鏈式的,多次調用使用AND連接
join(model,join_type=None,on=None)
參數:
- model-關聯的模型,必須有ForeignKeyField來關聯查詢上下文和關聯的模型.
- join_type-顯式指名關聯類型:JOIN.INNER,JOIN.LEFT_OUTER,JOIN.FULL
- on-如果兩個模型間有多個外鍵,指名使用哪個外鍵來關聯
返回類型:查詢實例
查詢上下文和join的參數來生成JOIN子句,建立新的查詢上下文.
例如:選擇admin發表的tweets和所屬users:
sq = SelectQuery(Tweet).join(User).where(User.is_admin == True)
把特殊的外鍵字段當做關聯選擇users.請看example app實例使用:
sq = SelectQuery(User).join(Relationship, on=Relationship.to_user)
switch(model)
參數:model-切換查詢上下文到模型
返回類型:返回新的查詢上下文的查詢
切換查詢上下文到指定的model,如果model沒有選擇或者在前面關聯會剖出異常.通常在單表執行多次連接時有用.
下面查詢選擇blog同時連接到entry和user:
sq = SelectQuery(Blog).join(Entry).switch(Blog).join(User)
alias(alias=None)
參數:alias(str) 查詢結果的昵稱
返回類型:查詢實例
sql()
返回類型:包含合適的SQL查詢和參數元組的二元元組
execute()
執行查詢
scalar([as_tuple=False])
參數:as_tuple(bool)-把行當作元組或單值返回
返回類型:結果行,一個元組或單值
提供了從選擇查詢里得到單值的方式,例如執行聚合:
>>> PageView.select(fn.Count(fn.Distinct(PageView.url))).scalar() 100 # <-- there are 100 distinct URLs in the pageview table
class SelectQuery(model_class,*selection)
目前為止peewee里最復雜的查詢類.它支持select語句中所有子句.
SelectQuery上方法可鏈式調用
SelectQuery實現了__iter__()方法,允許迭代返回結果實例
參數:
- model-執行查詢的模型
- selection-模型,字段,函數或表達式的列表
如果沒有selection提供,默認給的模型的所有字段都返回
例如選擇user實例,只有id和username被選擇.當迭代結果時,返回User模型實例:
sq = SelectQuery(User, User.id, User.username) for user in sq: print user.username
例如選擇users和每個人的tweets數量,User實例將擁有額外的count屬性,對應發表的tweets數量:
sq = (SelectQuery( User, User, fn.Count(Tweet.id).alias('count')) .join(Tweet) .group_by(User))
select(*selection)
參數:selection-表達式列表,可以是模型類,字段,若果不寫默認給定模型的所有字段
返回類型:SelectQuery
通常實例創建后將表明selection .這個方法之所以存在,是為了在查詢上修改select子句.
query = User.select() query = query.select(User.userna
from_(*args)
參數:args-一個或多個表達式,可以是Model或SelectQuery實例.如果為空,默認給定模型的表
返回類型:SelectQuery
# rather than a join, select from both tables and join with where. query = User.select().from_(User, Blog).where(Blog.user == User.id)
group_by(*clauses)
參數:clauses-表達式列表,可是模型類或單獨的字段實例
返回類型:SelectQuery
以單列或多列分組.如果模型類當參數,模型類所有字段將被當作分組字段.
例如:選擇users關聯tweets,並且以user分組,所以每個人的tweets可以被計算
sq = (User .select(User, fn.Count(Tweet.id).alias('count')) .join(Tweet) .group_by(User))
having(*expressions)
參數:expressions-一個或多個表達式列表
返回類型:SelectQuery
同上例:限制發表100以上tweets的用戶:
sq = (User .select(User, fn.Count(Tweet.id).alias('count')) .join(Tweet) .group_by(User) .having(fn.Count(Tweet.id) > 100))
order_by(*clauses)
參數:clauses-字段的列表,可以調用字段的field.[asc|desc]()
返回類型:SelectQuery
根據名字排序用戶
User.select().order_by(User.username)
根據user名字排序,然后根據發表時間排序選擇tweets
query = (Tweet .select() .join(User) .order_by( User.username, Tweet.created_date.desc()))
也可以使用+或-前綴來標明升降序:
query = (Tweet .select() .join(User) .order_by( +User.username, -Tweet.created_date))
復雜例子:先根據tweets發表數量,然后用戶名字排序:
tweet_ct = fn.Count(Tweet.id) sq = (User .select(User, tweet_ct.alias('count')) .join(Tweet) .group_by(User) .order_by(tweet_ct.desc(), User.username))
window(*windows)
參數:windows(Window)-一個或多個window定義.
在查詢上添加一個或若干個window定義
limit(num)
參數rs:num(int)-限制結果返回num個行
offset(num)
參數:num(int) -結果跳過num行
paginate(page-num,paginate_by=20)
參數:page_num-從1開始的頁數,用來將返回結果分頁
paginate_by-返回結果的每頁記錄數量
返回類型:SelectQuery
paginate是在查詢應用LIMIT和OFFSET的簡單方式
頁數切片是從1開始的,所以第一頁是page 1
distinct([is_distinct=True])
參數:is_distinct-下面將說明
返回類型:SelectQuery
表明查詢結果返回不同的行.相當於SELECT DISTINCT 查詢
注意:
is_distinct是個Boolean值,而不是DISTINCT
也可以用一個或多個表達式來生成DISTINCT ON查詢.例如:.distinct([Model.col1,Model.col2])
for_update([for_update=True,[,nowait=False]])
表明查詢更新行時加鎖.如果nowait設為True,數據庫如果不能獲得鎖將拋出OperationalError
naive()
返回類型:SelectQuery
標志查詢僅僅視圖為返回的每行重建單一模型.若多表參與參與查詢,返回的列直接分發到單個模型實例上.
通常這個方法對於給的數據庫游標來說加快其重建模型實例的速度.
注意:
當在大的數據結果集中做簡單的迭代時可以得到顯著的速度提升.
iterator()
返回類型:iterable
默認peewee將游標返回的數據行都緩存,這樣方便了多個迭代,切片,索引而不進行額外查詢.
但是當迭代大量的行時,這種緩存占據大量內存.使用iterator()可以不存儲所有的返回的模型實例從而節約內存.
# iterate over large number of rows. for obj in Stats.select().iterator(): # do something. pass
tuples()
返回類型:SelectQuery
將游標查詢結果只返回原生的元組數組.當你不想要模型實例而是簡單的結果時使用此方法.
dicts()
返回類型:SelectQuery
將游標結果只返回字典數組.當你只需要簡單的查詢結果時使用此方法.
aggregate_rows()
返回類型:SelectQuery
此方法提供了避免N+1查詢難題的一種方式
比如一個頁面需要展示一系列用戶及他們相關的tweets.你可以通過列出所有用戶然后為每一個用戶執行單獨的查詢找到他的tweets,這就是N+1行為,因為查詢次數取決於查詢出用戶的數量.明智的方法將盡量少執行查詢.Peewee提供了若干方法來解決此問題.
你可以使用prefetch()幫助器,它使用IN查詢子句來得到用戶的tweets.
另一種方法是在一個查詢里查出所有用戶和tweet行,然后再根據用戶的不同來聚合tweets/
原來查出的數據是這樣子的:
# user.id, user.username, tweet.id, tweet.user_id, tweet.message [1, 'charlie', 1, 1, 'hello'], [1, 'charlie', 2, 1, 'goodbye'], [2, 'no-tweets', NULL, NULL, NULL], [3, 'huey', 3, 3, 'meow'], [3, 'huey', 4, 3, 'purr'], [3, 'huey', 5, 3, 'hiss'],
我們可以推斷出JOIN子句中用戶數據將重復,因此我們減少重復用戶數據后,可以循環的收集用戶的tweets,然后透明的迭代用戶和他們的tweets
query = (User .select(User, Tweet) .join(Tweet, JOIN.LEFT_OUTER) .order_by(User.username, Tweet.id) .aggregate_rows()) # .aggregate_rows() tells peewee to de-dupe the rows. for user in query: print user.username for tweet in user.tweets: print ' ', tweet.message # Producing the following output: charlie hello goodbye huey meow purr hiss no-tweets
注意:
確保ORDER BY子句可以保證重復的數據出現在相關聯的行中
你也可以用作任意復雜的查詢,但是使用prefetch來執行復雜的查詢更有效。可以兩種方法嘗試一下看你的數據集適合哪種方式
annotate(related_model,aggregation=None)
參數:related_model-執行聚合的相關聯的模型, 必須通過ForeignKeyField連接
aggregation-聚合使用的類型:比如fn.Count(Tweet.id).alias('count')
返回類型:SelectQuery
通過在相關聯的模型上進行聚合來注釋查詢,例子:得到用戶和他們每個人的tweets數量
>>> User.select().annotate(Tweet)
如果 aggregate設為None,默認行為為fn.Count(related_model.id).alias('count'),但是也可以為其它:
user_latest = User.select().annotate(Tweet, fn.Max(Tweet.created_date).alias('latest'))
如果ForeignKeyField為nullable,LEFT OUTER 連接需要使用在join中:
query = (User .select() .join(Tweet, JOIN.LEFT_OUTER) .switch(User) # Switch query context back to `User`. .annotate(Tweet))
aggregate(aggregate)
參數:aggregation-表明聚合函數,例如:fn.Max(Tweet.created_date).
用聚合行的函數返回數量值,比如行數,或者特殊列的平均值.
count([clear_limit=False])
參數:clear_limit(bool)-在count前移除查詢里limit和offset子句
返回類型:查詢返回結果的行數
如果查詢里有GROUP BY,DISTINCT,LIMIT或者OFFSET子句時,wrapped_count()方法將使用.
>>> sq = SelectQuery(Tweet) >>> sq.count() 45 # number of tweets >>> deleted_tweets = sq.where(Tweet.status == DELETED) >>> deleted_tweets.count() 3 # number of tweets that are marked as deleted
wrapped_count([clear_limit=True])
參數:clear_limit(bool)-count前移除查詢里的limit和offset子句.
返回類型:查詢結果行數
在子查詢中包裝count查詢,當執行DISTINCT查詢或帶有GROUP BY子句時返回正確的結果
注意
count()將在遇到DISTINCT或GROUP BY自動使用wrapped_count()
exists()
返回類型:返回當前查詢是否返回有行的Boolean值,當優化查詢時,代替get()方法
sq = User.select().where(User.active == True) if sq.where(User.username == username, User.active == True).exists(): authenticated = True
get()
返回類型:模型實例或拋出DoesNotExist意外
從數據庫里得到滿足查詢條件的單行,如果沒有返回行拋出<model-class>.DoesNotExist意外
active = User.select().where(User.active == True) try: user = active.where(User.username == username).get() except User.DoesNotExist: user = None
此方法也通過Model API暴露,此情況下接收的參數翻譯為where子句:
user=User.get(User.active==True,User.username==username)
first()
返回類型:模型實例或None
得到查詢結果首記錄,結果會緩存以免將來會迭代整個查詢結果集
execute()
返回類型:QueryResultWrapper
執行查詢,返回QueryResultWrapper來迭代結果集.查詢結果由查詢內部管理,當可能改變
結果集的子句加進來時,查詢會重新執行.
__iter__()
執行查詢,返回模型實例迭代對象:
__len__()
返回查詢結果集中的行數量,若你只是想要數量,而不要結果集本身,可調用count()方法
注意:
SELECT查詢被執行,結果集被加載.
__getitem__(value)
參數:value-索引或者切片對象
返回模型實例結果集的切片.例如:得到首個記錄:
__or__(rhs)
參數:rhs-SelectQuery或CompoundSelect
返回類型:CompoundSelect
使用符號左右邊對象創建聯合查詢,結果同時包含左右邊的查詢結果.
customers = Customer.select(Customer.city).where(Customer.state == 'KS') stores = Store.select(Store.city).where(Store.state == 'KS') # Get all cities in kansas where we have either a customer or a store. all_cities = (customers | stores).order_by(SQL('city'))
SQLite不允許ORDER BY或LIMIT查詢子句在復合查詢的組件上,但是允許在最終結果集中使用這些子句.同樣對UNION(ALL),INTERSECT(),EXCEPT也是這樣.
__and__(rhs)
參數:rhs-SelectQuery或CompoundSelect
返回類型:CompoundSelect
創建INTERSECT查詢.結果集包含符號左右邊的結果的交集.
customers = Customer.select(Customer.city).where(Customer.state == 'KS') stores = Store.select(Store.city).where(Store.state == 'KS') # Get all cities in kanasas where we have both customers and stores. cities = (customers & stores).order_by(SQL('city'))
__sub__(rbs)
參數:rhs-SelectQuery或CompoundSelect
返回類型:CompoundSelect
創建EXCEPT查詢.結果返回符號包含在左邊查詢但是不包含在右邊查詢的結果.
customers = Customer.select(Customer.city).where(Customer.state == 'KS') stores = Store.select(Store.city).where(Store.state == 'KS') # Get all cities in kanasas where we have customers but no stores. cities = (customers - stores).order_by(SQL('city'))
__xor__(rhs)
參數:SelectQuery或CompoundSelect
返回類型:CompoundSelect
創建一個對稱差分查詢.結果包含或者在左邊查詢里的數據或者在右邊查詢里的數據,但沒有同時在兩邊查詢里的數據.
customers = Customer.select(Customer.city).where(Customer.state == 'KS') stores = Store.select(Store.city).where(Store.state == 'KS') # Get all cities in kanasas where we have either customers with no # store, or a store with no customers. cities = (customers ^ stores).order_by(SQL('city'))
class UpdateQuery(model_class,**kwargs)
參數:
- model-更新的模型
- kwargs-字段值對映射,用來更新列值
例子:用戶注冊過期將用戶標識為非活躍用戶:
uq = UpdateQuery(User, active=False).where(User.registration_expired == True) uq.execute() # Perform the actual update
例子:原子性更新:
atomic_update = UpdateQuery(PageCount, count = PageCount.count + 1).where( PageCount.url == url) atomic_update.execute() # will perform the actual update
execute()
返回類型:更新的行數
執行更新
returning(*returning)
參數:RETURNING-模型類,字段實例,函數或表達式的列表.如果沒有參數,給定模型的所有列都
將被選擇.清空所有存在的值,傳參數None
返回類型:給定模型的UpdateQuery
在查詢上添加RETURNING子句,會使UPDATE在實際更新的每行上計算值當作返回.
當更新執行時,不是返回受影響的行數,而是返回迭代器用來生成更新的對象.
當前只有PostgresqlDatabase支持此特性.
例子:
# Disable all users whose registration expired, and return the user # objects that were updated. query = (User .update(active=False) .where(User.registration_expired == True) .returning(User)) # We can iterate over the users that were updated. for updated_user in query.execute(): send_activation_email(updated_user.email)
tuples()
返回類型:UpdateQuery
此方法結合returning()調用來使用
更新結果以行元組返回
dicts()
返回類型:UpdateQuery
此方法結合returning()來使用
更新結果以行字典返回.每個字典映射列字段到值.
on_conflict([action=None])
加上SQL ON CONFLICT子句給UPDATE查詢,當conflict發生時會發生指定的動作。有效的動作有:
- ROLLBACK
- ABORT
- FAIL
- IGNORE
- REPLACE
指定None時時執行正常的UPDATE查詢
注意:
這個特性只支持SQLite 數據庫
class InsertQuery(model_class,[field_dict=None,[rows=None[,fields=None,[,query=None[,validate_fields=False]]]]])
創建模型的InsertQuery實例.
參數:
- field_dict(dict)-字段到值的映射.
- rows(iterable)-可迭代的字典,其為字段到值的映射
- fields(list)-插入值到的字段列表(僅僅與query參數聯合使用)
- query-用作SelectQuery的數據源
- validate_fields(bool)-檢查插入查詢中每一列在模型上都有對應的字段.如果validation開啟,但是驗證失敗,拋出KeyError異常.
基本使用例子:
>>> fields = {'username': 'admin', 'password': 'test', 'active': True} >>> iq = InsertQuery(User, fields) >>> iq.execute() # insert new row and return primary key 2L
插入多行:
users = [ {'username': 'charlie', 'active': True}, {'username': 'peewee', 'active': False}, {'username': 'huey', 'active': True}] iq = InsertQuery(User, rows=users) iq.execute()
從查詢數據源插入:
query = (User .select(User.username, fn.COUNT(Tweet.id)) .join(Tweet, JOIN.LEFT_OUTER) .group_by(User.username)) iq = InsertQuery( UserTweetDenorm, fields=[UserTweetDenorm.username, UserTweetDenorm.num_tweets], query=query) iq.execute()
execute()
返回類型:新行的主鍵
執行查詢
upsert([upsert=True])
在SQLite上執行INSERT 或REPLACE查詢.MySQL數據庫是歐陽REPLACE查詢.當前特性在Postgresql數據庫上不能用,但是9.5版本語法將添加此功能.
注意
此特性只在SQLite和MySQL上有效.
on_conflict([action=None])
在INSERT查詢上添加ON CONFLICT子句.指名為REPLACE等價於使用upsert方法.有效的動作有:
- ROLLBACK
- ABORT
- FAIL
- IGNORE
- REPLACE
當為None時表示動作為正常的INSERT查詢.
此特性只支持SQLite數據庫
return_id_list([return_id_list=True])
默認,批量插入時peewee不會返回插入的主鍵列表.但是如果數據庫支持通過INSERT...RETURNING來返回主鍵列表,此方法讓peewee來返回生成的IDs
注意:
當前只有Postgresql支持此行為.別的數據庫支持批量插入,簡單返回True
usernames = [ {'username': username} for username in ['charlie', 'huey', 'mickey']] query = User.insert_many(usernames).return_id_list() user_ids = query.execute() print user_ids # prints something like [1, 2, 3]
returning(*returning)
參數:returning-模型類,字段實例,函數或表達式列表.如果無參數,模型的所有列都返回,傳遞None當參數清除任何已存在的值.
返回類型:模型的InsertQuery
給查詢添加RETURNING子句,會在新插入的行中計算返回的值.
當執行查詢時,而不是返回插入的行的主鍵,將返回生成插入對象的迭代器.
當前此特性僅僅支持PostgresqlDatabase
# Create some users, retrieving the list of IDs assigned to them. query = (User .insert_many(list_of_user_data) .returning(User)) # We can iterate over the users that were created. for new_user in query.execute(): # Do something with the new user's ID... do_something(new_user.id)
tuples()
返回類型:InsertQuery
此方法只支持與returning()方法聯合使用
把插入對象的結果以行元組的形式返回
dicts()
返回類型:InsertQuery
此方法只支持與returning()方法聯合使用
把插入對象結果以字典列表的形式返回,其中字典是列到值的映射.
class DeleteQuery(model_class)
創建給定模型的DELETE查詢
注意:
DeleteQuery不會在外鍵上刪除或者不能保證遵守約束,所以小心使用
使用DeleteQuery刪除非活躍用戶:
dq = DeleteQuery(User).where(User.active == False)
execute()
返回類型:刪除的行數
執行查詢
returning(*returning)
參數:returning- 模型類,字段實例,函數和表達式的列表,如果沒有提供參數.給定模型的所有列都將返回,清除所有已存在的值,傳遞None
返回類型:給定模型的DeleteQuery
給查詢加上RETURNING子句,引起DELETE計算從數據庫中成功刪除的行的返回值.
當查詢執行時,不是返回刪除的行數,而是返回生成刪除對象的迭代器.
注意:
當前只有PostgresqlDatabase支持此特性.
例子:
# Create some users, retrieving the list of IDs assigned to them. query = (User .delete() .where(User.account_expired == True) .returning(User)) # We can iterate over the user objects that were deleted. for deleted_user in query.execute(): # Do something with the deleted user. notify_account_deleted(deleted_user.email)
tuples()
返回類型:DeleteQuery
注意:
此方法與returning()一起調用
刪除的結果返回以行元組列表返回.
dict()
返回類型:
DeleteQuery
此方法與returning()一起使用.
刪除的結果以映射列到值的字典列表形式返回
class RawQuery(model_class,sql,*params)
通過QueryResultsWrapper來執行任意的查詢,返回查詢的模型實例
注意:
通常使用此方法來執行高度優化的查詢
如果你執行參數化的查詢,比如根據你的數據庫使用正確的填充字符串.SQLite使用
'?',其它使用'%s'.
根據用戶名字選擇用戶:
>>> rq = RawQuery(User, 'SELECT * FROM users WHERE username = ?', 'admin') >>> for obj in rq.execute(): ... print obj <User: admin>
tuples()
返回類型:RawQuery
標志查詢是否從游標返回原生元組列表.當你不需要全部的模型實例時此方法很有用.
dicts()
返回類型:RawQuery
標志查詢是否從游標返回原生字典列表.當你不需要全部的模型實例時此方法很有用.
execute()
返回類型:
迭代結果集的QueryResultWrapper.結果集是給定模型的模型實例列表
執行查詢
class CompoundSelect(model_class,lhs,operator,rhs)
組合選擇查詢.
參數:
- model_class-返回模型的類型,默認是操作符左邊模型類型
- lhs-左邊查詢,SelectQuery或CompoundQuery
- operator-關聯兩個查詢的Node實例,例如SQL('UNION')
- rhs-右邊查詢,SelectQuery或CompoundQuery.
prefetch(sq,*subqueries)
參數:
- sq-SelectQuery實例
- subqueries-一個或多個SelectQuery實例來取得sq.你也可以傳遞模型實例,但是它們被轉換為SelectQuery.如果你想要指名與某個模型關聯,你可以傳遞(query_or_model,join_model)這樣的二元元組
返回類型:帶有預生成相關聯實例的SelectQuery
從子查詢中預先得到相應的實例數據,然后在外層查詢中賦給它們的父行.這個函數在子查詢中飢餓加載相關聯的實例.這是解決O(n)查詢問題的技巧,而不是執行k次子查詢.
例如.你有用戶列表,想要顯示他們的tweets:
# let's impost some small restrictions on our queries users = User.select().where(User.active == True) tweets = Tweet.select().where(Tweet.published == True) # this will perform 2 queries users_pf = prefetch(users, tweets) # now we can: for user in users_pf: print user.username for tweet in user.tweets_prefetch: print '- ', tweet.content
你可以預先得到任意數量的結果行.例如,我們有圖片網站,User->Photo->(Comments,Tags).用戶可以發表照片,照片有標簽和評論.如果我們想要得到一系列用戶,以及他們各自的照片,以及照片相關的評論和標簽:
users = User.select() published_photos = Photo.select().where(Photo.published == True) published_comments = Comment.select().where( (Comment.is_spam == False) & (Comment.num_flags < 3)) # note that we are just passing the Tag model -- it will be converted # to a query automatically users_pf = prefetch(users, published_photos, published_comments, Tag) # now we can iterate users, photos, and comments/tags for user in users_pf: for photo in user.photo_set_prefetch: for comment in photo.comment_set_prefetch: # ... for tag in photo.tag_set_prefetch: # ...
注意:
子查詢必須通過外鍵關聯,並且可以為任意深度.
關於更詳細的信息.可以看<<避免N+1查詢部分>>章節
若結果集很大prefetch()會消耗大量內存,並且你在做危險的事情時不會給你警告提示,所以取決於你的應用.另外,由於子查詢的語義不明,可能有時候你預得到的數據不是你想要的(例如,如果你在子查詢中使用LIMIT子句,可能應用到別的模型上)-如果你認為有bug的地方請向github提交報告.
Database 和子類
class Database(database[,threadlocals=True[,autocommit=True,[,fields=None,[,opt=None,[,autorollback=False,[,use_speedups=True,[**connect_kwargs]]]]]]])
參數:
- database-數據庫名稱(或者SQLite數據庫的文件名)
- threadlocals(bool)是否在threadlocal中存儲連接
- autocommit(bool)-通過調用execute()自動提交每一個查詢
- fields(dict)-db_field到數據庫列類型的映射,eg:'string'=>'varchar'
- ops(dict)-查詢編譯器理解的操作符到表達式的映射
- autorollback(bool)-當執行查詢發生錯誤時是否自動回滾
- use_speedups(bool)-使用Cython加速查詢性能
- connect_kwargs-任意的參數用在數據庫連接上
- connect_kwargs字典用在特定的參數,該參數向后直接傳遞到數據庫引擎上,讓你可以指名user,host,password.
注意:
如果當類定義時數據庫名稱未知,你可傳遞None當作數據庫名稱,然后數據庫將為deferred,此時
任何嘗試連接數據庫將拋出錯誤.調用Database.init()來初始化數據庫.
關於運行時數據庫配置的深度學習,請看運行時數據庫配置章節.
與支持的數據庫引擎的層次的API.數據庫類:
- 管理潛在的數據庫連接
- 執行查詢
- 管理事務和保存節點
- 創建表和索引,刪除表和索引
- 檢查數據庫
commit_select=False
在選擇查詢時是否執行提交,可以在有些數據庫引擎上避免隱式堆積的事務
compiler_class=QueryCompiler
編譯查詢的類
Compound_operations=['UNION','INTERSECT,'EXCEPT']
支持的符合查詢操作
Compound_select_parentheses=False
是否UNION或其他復合的SELECT查詢在查詢上加上括號
distinct_on=False
是否數據庫支持DISTINCT ON語句
drop_cascade=False
是否數據庫支持級聯地刪除表查詢
field_overrides={}
字段類型到數據庫列類型的映射.例如{'primary_key':'SERIAL'}
foreign_keys=True
是否給定的向后強制外鍵約束
for_update=False
是否給定的向后支持選擇行更新
for_update_nowait=False
是否給定的向后支持選擇行更新
insert_many=True
是否數據庫支持在INSERT查詢中多個VALUES子句
insert_returning=False
是否數據庫支持新增加的行返回主鍵
interpolation='?'
數據庫內插查詢參數的字符串
op_overrides={}
操作code和字符操作的映射{OP.LIKE:'LIKE BINARY'}
quote_char='"'
數據庫引擎應用名字的字符串
reversed_tables=[]
向后保留的表名字-如果在應用中遇到則會出現警告
returning_clause=False
是否數據庫支持在UPDATE,INSERT和DELETE查詢上的RERURNING子句
當前只支持PostgresqlDatabase數據庫.
看下面信息:
- UpdateQuery.returning()
- InsertQuery.returning()
- DeleteQuery.returning()
savepoints=True
是否給定向后支持保存節點.
sequences=False
是否給定向后支持序列
subquery_delete_same_table=True
是否向后支持使用從表中的子查詢來刪除行
window_functions=False
是否給定向后支持window函數.
init(database[,**connect_kwargs])
此方法用來初始化deferred數據庫.關於在運行時配置數據庫,請看運行時數據庫配置章節
參數:
- database-數據庫名稱(或sqlite的文件名)
- connect_kwargs-當連接數據庫引擎時的任意參數
connect()
建立到數據庫的連接
注意:
默認情況下,連接保存在threadlocal中,保證連接不被跨線程分享.為了取消此行為,可以初始化數據庫時設threadlocals=False.
close()
關閉數據庫連接
注意:
若你初始化時設置threadlocals=True,僅僅本地對調用的thread連接關閉.
initialize_connection(conn)
在新打開連接時得初始化其他.例如,如果你正使用SQLite想要開啟外鍵強制約束(默認關閉)
下面是如何用這個鈎子來加載SQLite擴展
class CustomSqliteDatabase(SqliteDatabase): def initialize_connection(self, conn): conn.load_extension('fts5')
get_conn()
返回類型:數據庫的連接,如果不存在創建一個連接
get_cursor()
返回類型:執行查詢的游標
last_insert_id(cursor,model)
- cursor-用於執行插入查詢的數據庫游標
- model-剛剛創建的模型類
返回類型-最近插入的實例的主鍵
rows_affected(cursor)
返回類型:最后查詢影響的行數
compiler()
返回類型:使用重載過的字段和操作的QueryCompiler實例
execute(clause)
參數:clause(Node)-Node實例或子類(例如:SelectQuery)
子句被編譯成SQL然后發給execute_sql()方法
execute_sql(sql[,params=None[,require_commit=True]])
參數:
- sql-sql查詢字符串
- params-用來填充的參數的列表或元組
注意:
你可以用set_autocommit()和Database.get_autocommit()配置查詢是否自動提交.
begin()
開啟新的事務.默認沒有實現,因為不是DB_API 2.0的一部分,但是為了API兼容性提供了.
commit()
在當前活動連接上調用commit(),提交當前事務
rollback()
在當前活動連接上調用rollback(),回滾當前事務.
set_autocommit(autocommit)
參數:
autocommit-是否開啟自動提交的Boolean值
get_autocommit()
返回類型:是否自動提交開啟的Boolean值
get_tables([schema=None])
返回類型:數據庫中的表名列表
get_indexes(table,[,schema=None])
返回類型:IndexMetadata實例列表,代表給定表的索引
get_columns(table[,schema=None])
返回類型:ColumnMetadata實例列表,表示給定表的列
get_primary_keys(table[,schema=None])
返回類型:給定表的主鍵列名稱列表
get_foreign_keys(table,[,schema=None])
返回類型:ForeignKeyMetadata實例列表,代表給定表的外鍵
sequence_exists(sequence_name)
返回類型:Boolean值,表示序列是否存在
create_table(model_class[,safe=True])
參數
- model_class-模型類
- safe(bool)-為True時,表將不創建如果已經存在.
注意:
不像Model.create_table(),此方法不創建索引和約束.這個方法只是創建表本身.如果你想要同時創建索引和約束,使用Model.createtable或Database.create_tables().
create_index(model_class,fields[,unique=False])
參數:
- model_class -將要創建索引的模型表
- fields-創建索引的字段(或字段實例或字段名稱)
- unique-索引是否唯一
create_foreign_key(model_class,field[,constraint=None])
參數:
- model_class-在哪個Model表上創建外鍵約束
- field-Field對象
- constraint(str)-外鍵約束名稱
使用ALTER TABLE來手動的創建外鍵約束.當創建循環外鍵依賴時非常有用.例子:
DeferredPost = DeferredRelation() class User(Model): username = CharField() favorite_post = ForeignKeyField(DeferredPost, null=True) class Post(Model): title = CharField() author = ForeignKeyField(User, related_name='posts') DeferredPost.set_model(Post) # Create tables. The foreign key from Post -> User will be created # automatically, but the foreign key from User -> Post must be added # manually. User.create_table() Post.create_table() # Manually add the foreign key constraint on `User`, since we could # not add it until we had created the `Post` table. db.create_foreign_key(User, User.favorite_post)
create_sequence(sequence_name)
參數:sequence_name-將要創建的序列名稱
注意:
僅僅支持有序列支持的數據庫引擎
drop_table(model_class[,fail_silently=False[,cascade=False]])
參數:
- model_class-要刪除的表的模型
- fair_silently(bool)-如果為True,查詢將增加一條IF EXISTS子句
- cascade(bool)-選項CASCADE的刪除表
drop_sequence(sequence_name)
參數:
sequence_name-刪除的序列的名字
注意:
僅僅支持有序列支持支持的數據庫引擎
create_tables(model[,safe=False])
參數:
- model(lsit)-模型列表
- safe(bool)-檢查是否表已存在,然后再去創建表
此方法應該在用作創建表,因為它會解析模型的依賴關系,所以確保表的創建順序.此方法也創建模型上的索引和約束.
用法:
db.create_tables([User, Tweet, Something], safe=True)
drop_tables(models[,safe=False[,cascade=False]])
參數:
- models(list)-模型列表
- safe(bool)-檢查表是否存在在試圖刪除前
- cascade(bool)-選項CASCASE刪除表
db.drop_tables([User, Tweet, Something], safe=True)
這個方法用於刪除表,因為它將解析表之間的依賴關系,確保按照正確的順序刪除.
atomic()
在事務或保存節點中執行語句.外層的調用將使用事務,任何嵌套的內層調用使用保存節點.
atomic可以用作上下文管理器或者裝飾器.
注意:
大多數情況下,當你想要在事務中查詢時總是使用atomic()是好辦法.使用atomic的方便之處是你不必手動跟蹤事務棧的深度,它將為你管理事務棧.
用作上下文管理器代碼:
with db.atomic() as txn: perform_some_operations() with db.atomic() as nested_txn: do_other_things() if something_bad_happened(): # Roll back these changes, but preserve the changes # made in the outer block. nested_txn.rollback()
用作裝飾器代碼:
@db.atomic() def create_user(username): # This function will execute in a transaction/savepoint. return User.create(username=username)
transaction()
在事務中執行語句,可用作上下文管理器或裝飾器.如果錯誤拋出在包裝的語句塊中,事務回滾,否則語句在完成后提交.事務語句塊中的事務通過調用rollback()或commit()可以顯式的回滾或提交.如果你手動的回滾,一個新事務將自動開始.
用transaction可以包裝語句塊-數據庫將保持棧狀態,僅僅語句塊到達最外層的函數或塊結構時才提交.
用作上下文管理器的例子:
# delete a blog instance and all its associated entries, but # do so within a transaction with database.transaction(): blog.delete_instance(recursive=True) # Explicitly roll back a transaction. with database.transaction() as txn: do_some_stuff() if something_bad_happened(): # Roll back any changes made within this block. txn.rollback()
用作裝飾器的例子:
@database.transaction() def transfer_money(from_acct, to_acct, amt): from_acct.charge(amt) to_acct.pay(amt) return amt
commit_on_success(func)
注意:
用atomic()或者transaction()代替
savepoint([sid=None])
使用上下文管理器或者裝飾器來執行保存節點中的語句.如果在包裝的語句塊中出現異常,保存節點將回滾,否則語句提交.和transaction()不同,保存節點可以顯式的回滾和提交,分別調用rollback()和commit().如果你手動的提交或回滾,新的保存節點不會創建.
保存節點可以認為是嵌套的事務.
參數:sid(str)-選擇性的字符串來代表這個保存節點.
用作上下文管理器的例子:
with db.transaction() as txn: do_some_stuff() with db.savepoint() as sp1: do_more_things() with db.savepoint() as sp2: even_more() # Oops, something bad happened, roll back # just the changes made in this block. if something_bad_happened(): sp2.rollback()
execution_context([with_transaction=True])
創建一個ExecutionContext上下文管理器或裝飾器.用ExecutionContext包裝的語句將使用各自的連接.默認情況下,包裝的語句在一個事務里執行,可以通過指定參數with_transaction=False來關閉此功能.
關於ExecutionContext的詳細解釋,請看<<高級連接管理>>章節.
注意:
ExecutionContext是新功能,沒有測試完全.
classmethod register_fields(fields)
為數據類注冊字段映射.用於注冊自定義字段或者重載默認字段映射.
參數:
- fields(dict)-db_field到列類型的映射
classmethod register_ops(ops)
注冊能被QueryComplier理解的操作符到等價的SQL語句的映射.例如:{OP.EQ:'='}.用於擴展字段的比較類型.
extract_date(date_part,date_field)
返回從日期字段中抽取日期一部分的表達式.例如,從DateTimeField里提取年份.
參數:
- date_part(str)-想得到的日期屬性.有效的選項有:'year','month','day','hour','minute'以及'second'
- date_field(Field)-存儲datetime,date或time的字段實例
返回類型:表達式對象
truncate_date(date_part,date_field)
返回截短date/datetime到指定的方案的合適的表達式.例如,用於將timestamps按天來分組.
參數:
- date_part(str)-截短到的日期部分,有效的選項有:'year','month','day','hour','minute','second'
- date_field(Field)-存儲datetime,date或time的字段實例
返回類型:表達式對象.
例子:
# Get tweets from today. tweets = Tweet.select().where( db.truncate_date('day', Tweet.timestamp) == datetime.date.today())
class SqliteDatabase(Database)
Database 與sqlite3驅動或pysqlite2.除了默認的數據庫參數,SqliteDatabase可以接收journal_mode參數來配置journal模式
注意:
如果你在系統同時安裝了sqllite3和pysqlite2,peewee將使用指向SQLite最新版本的那個模塊.
SQLite是Peewee唯一支持的可在宿主應用中高度可定制的數據庫.意味着你可以用Python寫自己的函數和聚合,然后在SQL查詢中調用.這個特性可以通過SqliteExtDatabase來獲得學習.強烈推薦你使用SqliteExtDatabase,它暴露了使得SQLite更強大的許多特性.
自定義參數:
參數:
- journal_mode(str)-日志模式
- pragmas(list)-包含PGRAMA語句的二元元組列表,以便處理與新連接的競爭
SQLite允許通過PRAGMA語句來在運行時配置許多參數.PRAGMA用來與新連接到來時處理情形.在新連接到來時運行一個或多個PRAGMA語句,你可以將它們以包含PRAGMA名字和值的二元元組列表的形式指名:
db = SqliteDatabase('my_app.db', pragmas=( ('journal_mode', 'WAL'), ('cache_size', 10000), ('mmap_size', 1024 * 1024 * 32), ))
insert_many=True 如果使用SQLite 3.7.11.0或更高版本
class MySQLDatabase(Database)
Database 與MySQLdb或pymysql一起工作的子類.
commit_select=True
compound_operations=['UNION']
for_update=True
subquery_delete_same_table=False
class PostgresqlDatabase(Database)
Database 子類與psycopg2驅動器一起工作
commit_select=True
Compound_select_parentheses=True
distinct_on=True
for_update=True
for_update_nowait=True
insert_returning=True
returning_clause=True
sequences=True
window_functions=True
register_unicode=True
控制是否UNICODE和UNICODEARRAY psycopg2擴展模塊自動載入
(Transaction,Savepoint和ExecutionContext事務,保存節點和執行上下文
最簡單使用事務和保存節點的方式是使用Database.atomic().atomic()方法根據嵌套的層次創建transaction或者savepoint.
with db.atomic() as txn: # The outer-most call will be a transaction. with db.atomic() as sp: # Nested calls will be savepoints instead. execute_some_statements()
class transaction(database)
上下文管理器封裝了數據庫事務.在包裝以后語句塊中的語句將在沒有意外拋出時在最后提交,否則事務回滾.
注意:
事務應該不嵌套,以免在嵌套的語句塊中發生意外時導致未知行為.如果你想要嵌套事務,使用atomic()方法,會在最外層創建事務,嵌套中使用保存節點.
實際中你最好不用transaction對象,而是使用Database.transaction()方法.
commit()
手動提交掛起的更改,然后開始新事務
rollback()
手動回滾掛起的更改,然后開始新的事務.
class savepoint(database,[sid=None])
上下文管理器封裝了保存節點(嵌套事務).在包裝的語句中在沒有意外拋出情況下最后提交事務,否則最后回滾事務.
注意:
保存節點必須在一個事務中使用,所以推薦使用使用atomic()方法來代替手動管理事務+保存節點的上下文棧.
實際中,最好不直接創建savepoint,而采用Database.savepoint()方法.
commit()
手動提交任何掛起的更改.如果保存節點手動提交並且有改變,它們將在最外層的上下文中執行.
rollback()
手動回滾任何掛起的更改,如果保存節點手動回滾並且有更改,它們將在最外層上下文中執行.
class ExecutionContext(database[,with_transaction=True])
ExecutionContext顯式提供了專用的連接來運行SQL.典型地每個線程使用單一的數據庫連接,但是如果你想要強制性的使用新數據庫連接.這時你可以使用ExecutionContext.在包裝的語句塊中默認語句在一個事務中運行,你可以通過with_transaction=False來不用事務.
注意:
而不是直接使用ExecutionContext,使用Database.execution_context().
例子:
conn = db.get_conn() with db.execution_context(): # This will be a new connection object. If you are using the # connection pool, it may be an unused connection from the pool. ctx_conn = db.get_conn() # This statement is executed using the new `ctx_conn`. User.create(username='huey') # At the end of the wrapped block, the connection will be closed and the # transaction, if one exists, will be committed. # This statement is executed using the regular `conn`. User.create(username='mickey')
class Using(database,models,[,with_transaction=True])
在包裝語句期間,所有models的查詢都可用這里指定的數據庫.通過指定with_transaction=True,所有的查詢可以在事務里運行.
Using提供了,在一系列模型上運行查詢,但是使用手動指定的數據庫.
參數:
- database-Database實例
- models-使用此數據庫的一系列模型類
- with_transaction-是否包裝的語句在事務中運行
Metadata 類型
class IndexMetadata(name,sql,columns,unique,table)
name
索引名字
sql
SQL查詢去生成索引
columns
索引包含的列
unique
表示索引是否為唯一約束
table
包含索引的表名
class ColumnMetadata(name,data_ype,null,primary_key,table)
name
列名
data_type
列類型
null
NULL是否允許
primary_key
是否列為主鍵
table
包含列的表名
class ForeignKeyMetadata(column,dest_table,dest_column,table)
column
包含外鍵的列
dest_table
引用此外鍵的表
dest_column
引用此外鍵的列
table
包含此外鍵的表名
Misc
class fn
幫助器轉換任意的函數調用到SQL函數調用
peewee中使用表達式函數,使用fn對象。它'.'操作符右邊的事物被當作函數對待.你可以
你可以將函數傳遞任意參數,參數也可以為其它有效的表達式.
例如:
Peewee expression | Equivalent SQL |
---|---|
fn.Count(Tweet.id).alias('count') |
Count(t1."id") AS count |
fn.Lower(fn.Substr(User.username, 1, 1)) |
Lower(Substr(t1."username", 1, 1)) |
fn.Rand().alias('random') |
Rand() AS random |
fn.Stddev(Employee.salary).alias('sdv') |
Stddev(t1."salary") AS sdv |
over([partition_by=None,[,order_by=None[,window=None]]])
基本的SQL窗口函數.
參數:
- partition_by(list)-分區依據的Node實例列表
- order_by(list)-用來排序的Node實例列表
- window(Window)-聚合的Window實例
例子:
# Get the list of employees and the average salary for their dept. query = (Employee .select( Employee.name, Employee.department, Employee.salary, fn.Avg(Employee.salary).over( partition_by=[Employee.department])) .order_by(Employee.name)) # Rank employees by salary. query = (Employee .select( Employee.name, Employee.salary, fn.rank().over( order_by=[Employee.salary]))) # Get a list of page-views, along with avg pageviews for that day. query = (PageView .select( PageView.url, PageView.timestamp, fn.Count(PageView.id).over( partition_by=[fn.date_trunc( 'day', PageView.timestamp)])) .order_by(PageView.timestamp)) # Same as above but using a window class. window = Window(partition_by=[fn.date_trunc('day', PageView.timestamp)]) query = (PageView .select( PageView.url, PageView.timestamp, fn.Count(PageView.id).over(window=window)) .window(window) # Need to include our Window here. .order_by(PageView.timestamp))
class SQL(sql,*params)
在peewee查詢上添加SQL片段.例如,你需要引用一個別名的查詢.
參數:
- sql(str)-任意的SQL字符串
- params-任意的查詢參數
# Retrieve user table and "annotate" it with a count of tweets for each # user. query = (User .select(User, fn.Count(Tweet.id).alias('ct')) .join(Tweet, JOIN.LEFT_OUTER) .group_by(User)) # Sort the users by number of tweets. query = query.order_by(SQL('ct DESC'))
class Window([partition_by=None[,order_by=None]])
創建WINDOW定義
參數:
- partition_by(list)-分區的Node實例列表
- order_by(list)-用來排序的Node實例列表
例子:
# Get the list of employees and the average salary for their dept. window = Window(partition_by=[Employee.department]).alias('dept_w') query = (Employee .select( Employee.name, Employee.department, Employee.salary, fn.Avg(Employee.salary).over(window)) .window(window) .order_by(Employee.name))
class DeferredRelation
用來引用尚未創建的模型類.作為外鍵關聯的模型的別名.在循環引用有用.
DeferredPost = DeferredRelation() class User(Model): username = CharField() # `Post` is not available yet, it is declared below. favorite_post = ForeignKeyField(DeferredPost, null=True) class Post(Model): # `Post` comes after `User` since it refers to `User`. user = ForeignKeyField(User) title = CharField() DeferredPost.set_model(Post) # Post is now available.
set_model(model)
用合適的模型類代替占位符
class Proxy
Proxy類在當你想要推遲對象的初始化時非常有用,例如,你想要定義你的模型,但是你在運行上線前還未確定數據庫引擎.
例子:
database_proxy = Proxy() # Create a proxy for our db. class BaseModel(Model): class Meta: database = database_proxy # Use proxy for our DB. class User(BaseModel): username = CharField() # Based on configuration, use a different database. if app.config['DEBUG']: database = SqliteDatabase('local.db') elif app.config['TESTING']: database = SqliteDatabase(':memory:') else: database = PostgresqlDatabase('mega_production_db') # Configure our proxy to use the db we specified in config. database_proxy.initialize(database)
initialize(obj)
參數:代理的對象
一旦初始化,obj上的屬性和方法可以直接通過Proxy實例來訪問.
class Node
Node類是查詢的所有組件的父類,形成了peewee的基本表達式API的基礎,下面的類就都繼承自Node:
SelectQuery
,UpdateQuery
,InsertQuery
,DeleteQuery
, andRawQuery
.Field
Func
(andfn()
)SQL
Expression
Param
Window
Clause
Entity
Check
重載的操作符:
- 位操作符 and -and和or-(& 和 |):使用當作連接符連接多個node
- +,-,*,/和^ (加,減,乘,除和異或)
- ==,!=,<,<=,>,>=:使用它們創建一個二元表達式.
- <<:創建IN表達式
- >>:創建IS表達式.
- % 和** :LIKE和ILIKE
contains(rhs)
使用大小寫不敏感的字符串查詢創建二元表達式
startswith(rhs)
使用大小寫不敏感的前綴搜索創建二元表達式
endswith(rhs)
使用大小寫不敏感的后綴搜索創建二元表達式
between(low,high)
創建匹配滿足low和high之間的表達式
regexp(expression)
基於正則表達式匹配
concat(rhs)
將當前node和rhs連接.
is_null([is_null=True])
創建表達式來測試Node是否為NULL
# Find all categories whose parent column is NULL. root_nodes = Category.select().where(Category.parent.is_null()) # Find all categores whose parent is NOT NULL. child_nodes = Category.select().where(Category.parent.is_null(False))
為了簡化,peewee生成對應的正確的SQL.is_null()方法提供閱讀簡單性.
__invert__()
取node的相反.這將粗略的轉成NOT(<node>)
alias([name=None])
將node定義別名.這轉換為<node> AS <name>
asc()
應用升序到node上,轉換為<node> ASC.
desc()
應用降序到node上,轉換為<node> DESC
bind_to(model_class)
將表達式的結果綁定到指定的模型類型上.當表達式的結果放在指定的關聯實例上,需要給select添加表達式時非常有用.
classmethod extend([name=None,[,clone=False]])
在Node和它的子類上添加裝飾函數作為新方法,當自己在所有的node類型上實現了特定的新特性時非常有用.
參數:
- name(str)-方法名稱,若沒有則包裝的函數名稱被使用
- clone(bool)-此方法是否返回克隆版本.當方法改變node的內部狀態時通常設為true
例子:
# Add a `cast()` method to all nodes using the '::' operator. PostgresqlDatabase.register_ops({'::', '::'}) @Node.extend() def cast(self, as_type): return Expression(self, '::', SQL(as_type)) # Let's pretend we want to find all data points whose numbers # are palindromes. Note that we can use the new *cast* method # on both fields and with the `fn` helper: reverse_val = fn.REVERSE(DataModel.value.cast('str')).cast('int') query = (DataPoint .select() .where(DataPoint.value == reverse_val))
調動類的delattr方法把原來定義的方法作為參數移除擴展的方法.