官方文檔地址:http://docs.peewee-orm.com/en/latest/
1.創建模型
import peewee as pw
# 這里用的是postgresql
db = pw.PostgresqlDatabase(database='test', user='yang', host='192.168.2.1', port=5433, password='****')
class BaseModel(pw.Model):
"""基礎模型"""
# 在此類定義通用方法,方便繼承調用
class Meta:
database = db
class User(BaseModel):
"""用戶表"""
class Meta:
table_name = 'user'
id = pw.AutoField() # 主鍵
name = pw.CharField(help_text='用戶名稱')
sex = pw.CharField(help_text='性別')
phone = pw.CharField(help_text='電話號碼')
parent_id = pw.IntegerField(help_text='')
pid = pw.IntegerField(help_text='地區表id')
gid = pw.IntegerField(help_text='年級表id')
class Province(BaseModel):
"""省份表"""
class Meta:
table_name = 'province'
id = pw.AutoField() # 主鍵
name = pw.CharField(help_text='省名稱')
class Grade(BaseModel):
"""年級表"""
class Meta:
table_name = 'grade'
id = pw.AutoField() # 主鍵
name = pw.CharField(help_text='年級名')
2.表格操作
2.1 創建表格
# 創建表有兩種方式:
# 第一種,單個表的創建表
User.create_table()
Province.create_table()
Grade.create_table()
# 第二種,一次性創建多個表
db.create_tables([User,Province,Grade])
2.2 刪除表格
# 和創建表一樣,刪除表也有兩種方式:
# 第一種,單個表的創建表
User.drop_table()
Province.drop_table()
Grade.drop_table()
# 第二種,一次性創建多個表
db.drop_tables([User,Province,Grade])
2.3 修改表名
from playhouse.migrate import PostgresqlMigrator, migrate
migrator = PostgresqlMigrator(db)
# 執行操作有兩種方式.
# 第一種
migrate(migrator.rename_table('舊表名', '新表名'))
# 第二種
migrator.rename_table('舊表名', '新表名').run()
3.字段的增刪改查
修改字段的同時一定要把對應的模型同步修改,以免造成模型和表字段名不一致的問題
3.1增
from playhouse.migrate import PostgresqlMigrator, migrate
migrator = PostgresqlMigrator(db)
# 增加字段,參數分別為表名,字段名,字段類型,新增字段的時候,必須指定默認值或者可以為空
migrator.add_column('table_name', 'column_name', 字段類型)
# 增刪改執行操作都有兩種方式
# 第一種 使用migrate方法遷移,可以一次性增加多個字段
migrate(migrator.add_column('user', 'age',pw.IntegerField(null=True,help_text='年齡')),
migrator.add_column('user', 'school',pw.CharField(null=True,help_text='學校')))
#第二種,使用自身的run方法
migrator.add_column('user', 'age', pw.IntegerField(null=True,help_text='年齡')).run()
migrator.add_column('user', 'school', pw.CharField(default='',help_text='學校')).run()
3.2刪
# 和增一樣,有兩種執行方式,這里就只寫一種,參數為表名和字段名
migrate(migrator.drop_column('grade', 'school'),
migrator.drop_column('user', 'age'))
3.3改
# 修改字段名,參數為表名,字段名,新字段名
migrate(migrator.rename_column('grade', 'name', 'new_name'))
3.4查
print(User._meta.fields)
# {'id': <AutoField: User.id>,
# 'name': <CharField: User.name>,
# 'sex': <CharField: User.sex>,
# 'phone': <IntegerField: User.phone>,
# 'pid': <IntegerField: User.pid>,
# 'gid': <IntegerField: User.gid>}
print(User._meta.table_name)
# 'user'
4.索引相關操作
4.1 添加索引
from playhouse.migrate import PostgresqlMigrator, migrate
migrator = PostgresqlMigrator(db)
# 1.指定表名,字段名(集合),是否為唯一索引
migrator.add_index('user', ['name'], unique=True).run()
# 2.在字段里添加索引
class Test1(BaseModel):
"""測試表"""
class Meta:
table_name = 'test1'
id = pw.AutoField() # 主鍵
name = pw.CharField(unique=True, help_text='用戶名稱')
# 3.在元信息里指定索引
class Test1(BaseModel):
"""測試表"""
class Meta:
table_name = 'test2'
indexes = (
(('name',), False), # 字段名(元組),布爾值:是否是唯一索引
(('xxx', 'yyy'), True), # 聯合唯一索引
)
id = pw.AutoField() # 主鍵
name = pw.CharField(help_text='用戶名稱')
xxx = pw.CharField(help_text='用戶名稱')
yyy = pw.CharField(help_text='用戶名稱')
4.2查看索引
# 指定表名
db.get_indexes('user')
4.3刪除索引
# 指定表名和字段名
migrator.drop_index('user', ['name']).run()
5.數據增刪改查
peewee的增刪改查和sql非常相似,幾乎可以說sql一模一樣,用sql能查詢的用peewee基本都能實現
5.1增
# 添加數據有很多種方式,主要是使用create,save,insert,insert_many
# create會返回添加的模型
# 進行多條數據增刪改的時候,使用事務操作
with db.atomic() as transaction:
Grade.create(id=1, name='一年級')
Grade.create(id=2, name='二年級')
Province.create(id=1, name='上海')
Province.create(id=1, name='北京')
User.create(id=1, name='tom', sex='male', phone=123, pid=1, gid=1)
User.create(id=2, name='jack', sex='female', phone=123, pid=1, gid=1)
User.create(id=3, name='mary', sex='male', phone=123, place=2, gid=2)
User.create(id=4, name='jerry', sex='male', phone=123, place=1, gid=2)
# 批量添加,效率要高一點
# 返回添加的模型id元組組成的元組 ((1,),(2,),(3,)...)
User.insert_many([{字段名:字段值},...]).execute()
5.2 刪
User.delete().where(User.id == 1).execute()
5.3 改
User.update(column=value).where(User.id == 2).execute()
# 批量修改相同的值
User.update(column=value).where(User.id << [1,2,3]).execute()
# 批量修改不同的值,分別用orm對應sql兩種寫法
# 假設user表新增一個school_name字段,需要對這個字段根據學校id全表更新相應的值
# sql寫法
UPDATE user SET
school_name= (SELECT name FROM school WHERE school.id=user.school_id);
# -- OR -- 下面這種sql可以先把查詢結果當作一個表,當修改結果需要比較復雜的查詢才能得到時,可以用下面這種sql
WITH new_school(school_id, school_name) AS (
SELECT school.id, school.name
FROM school)
UPDATE user
SET school_name= new_school.school_name
FROM new_school
WHERE user.school_id= new_school.school_id;
# orm寫法
sq1 = School.select(School.name).where(User.school_id==School.id)
res = (User
.update(school_name=sq1)
.execute())
# OR:
cte = (School
.select(School.id, School.name)
.cte('new_school', columns=('school_id', 'school_name')))
res = (User
.update(school_name=cte.c.school_name)
.with_cte(cte)
.from_(cte)
.where(User.school_id==cte.c.school_id)
.execute())
5.4 查
查的操作太多,建議官方文檔 Peewee
這里大致介紹一下常用語法
5.4.1 常規查詢
# 1.常規查詢,和sql簡直一樣,往后面點就完事了
select_queries = User.select(...).where(...).order_by(...).limit(...)...
5.4.2 分組查詢
from peewee import fn
# fn可以調用sql中的所有函數
# 和sql一樣,查詢的字段必須是分組的字段,查詢其他字段需要使用聚合函數
select_queries = User.select(User.name, fn.MAX(id)).group_by(User.name)
5.4.3 連表查詢
在有外鍵的情況下,可以不指定連表字段,會自動使用外鍵連接
# 1.內連接
select_queries = (User.select(User.name, Grade.name)
.join(Grade, on=(User.gid==Grade.id), attr='grade'))
for query in select_queries:
user_name = query.name
grade_id = query.grade.name
# 多個表連接的時候,可以使用switch(User),使上下文切換回User,屬性添加在user上面
select_queries = (User.select(User.name, Grade.name, Province.name)
.join(Grade, on=(User.gid==Grade.id), attr='grade')
.switch(Province)
.join(Province, on=(User.pid==Province.id), attr='province'))
for query in select_queries:
user_name = query.name
grade_id = query.grade.name
province_name = query.province.name
# 如果不使用switch,則 province_name = query.grade.province.name
# 2.左連接
from peewee import JOIN
select_queries = (User.select(User.name, Grade.name)
.join(Grade, JOIN.LEFT_OUTER, on=(User.gid==Grade.id), attr='grade'))
for query in select_queries:
user_name = query.name
# 由於使用左連接,query不一定有grade屬性
grade_name = query.grade.name if hasattr(query, 'grade') else None
# 3.自連接 自連接需要先給表取個別名
user_temp = User.alias('user_temp')
select_queries = (User.select(User.name, user_temp.name)
.join(user_temp, on=(User.parent_id == user_temp.id), attr='user_temp'))
for query in select_queries:
user_name = query.name
parent_name = query.user_temp.name
5.4.4 子查詢
# 將查詢結果當作一張新表進行連接
sub_queries = User.select()
user_queries = (User.select(User.name, sub_queries.c.name)
.join(sub_queries , on=(sub_queries.c.id == User.id), attr='temp'))
for query in user_queries:
user_name = query.name
user_temp_name = query.temp.name
# 將查詢結果當作一張新表進行查找
# 寫法1
from peewee import Select
user_queries = Select(columns=[sub_queries.c.id, sub_queries.c.name]).from_(sub_queries).execute(db)
for query in user_queries:
id = query['id']
name = query['name']
...
# 寫法2,這種寫法更方便好用
user_queries = sub_queries.select_from(sub_queries.c.id, sub_queries.c.name)
for query in user_queries:
id = query.id
name = query.name
...
5.4.5 fn
# fn是一個比較強大的對象,可以調用sql中的所有函數
# 如需要查出相同名字出現兩條記錄的人
from peewee import fn
select_queries = User.select(User.name).group_by(User.name).having(fn.COUNT(User.id) == 2)
5.4.6 SQL
# SQL的作用是可以peewee和sql結合使用,使用orm的同時,可以寫一小段sql一起使用
# 如需要查出每個名字分組的第一條記錄
from peewee import SQL
sql = "row_number() over(partition by t1.name order by t1.id)"
select_queries = User.select(User, SQL(sql).alias("rn"))
#上面這個查詢轉換成sql:
select t1.*,row_number() over(partition by t1.name order by t1.id) as rn from user t1;
5.4.7 union,intersect,except_
# 表上下連接,自動去重,不想去重的話使用union_all
# 請注意字段個數必須一樣,字段名已第一個查詢為主
user_queries1 = User.select()
user_queries2 = User.select()
union_queries = user_queries1.union(user_queries2) # 並集
intersect_queries = user_queries1.intersect(user_queries2) #交集
except_queries = user_queries1.except_(user_queries2) #差集
5.5 原生sql執行
# 執行原生sql,進行增刪改查的操作
sql = '''insert into user values(1, '一年級')"""
db.execute_sql(sql)