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