peewee的使用


官方文檔地址: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)


免責聲明!

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



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