orm之peewee

peewee是一款orm框架,为什么选择peewee,是因为它比较简单和Django比较类似,而且还有一个async-peewee,可以进行异步化。

如何定义model和生成表

'''
我们要定义两张表,一张商品,一张商品供应商。商品表里面有一个外键对应商品供应商
'''
import peewee
 
# 第一个参数是我们数据库的名字,其他的参数则跟pymysql一样
db = peewee.MySQLDatabase("satori", host="localhost", port=3306, user="root", password="zgghyys123")
 
 
# 定义供应商
class Supplier(peewee.Model):
    # max_length:最大长度。verbose_name:注释信息。index:是否设置为索引
    name = peewee.CharField(max_length=100, verbose_name="供应商名称", index=True)
    address = peewee.CharField(max_length=200, verbose_name="供应商地址")
    phone = peewee.CharField(max_length=11, verbose_name="联系电话")
 
    class Meta:
        # 和Django比较类似,绑定一个数据库实例
        database = db
        # 设置表名
        table_name = "supplier"
 
 
class Goods(peewee.Model):
    # 我们这里没有指定主键,那么会默认创建一个id列作为主键,如果SQLAlchemy的话必须要自己指定
    name = peewee.CharField(max_length=100, verbose_name="商品名称", index=True)
    click_num = peewee.IntegerField(default=0, verbose_name="点击数")
    goods_num = peewee.IntegerField(default=0, verbose_name="库存")
    price = peewee.FloatField(default=0.0, verbose_name="价格")
    brief = peewee.TextField(verbose_name="商品简介")
    # 绑定外键,和Django一样
    # backref:反向引用。既然定义了外键,我们可以在Goods可以通过supplier访问到Supplier。
    # 那么如何通过Supplier访问到Goods呢?那么就可以通过backref指定的goods来访问。这个SQLAlchemy也是一样的
    # 但SQLAlchemy中,我们不仅要自己指定外键,并且定义反向引用的时候还要导入一个relationship
 
    supplier = peewee.ForeignKeyField(Supplier, verbose_name="供应商", backref="goods")
 
    class Meta:
        database = db
        table_name = "goods"
 
 
if __name__ == '__main__':
    # 以上表便定义完成了,下面映射到数据库
    # 直接使用db.create_tables即可,将要映射成表的模型放在列表里传进去
    db.create_tables([Goods, Supplier])

orm之peewee

model的数据保存

# 导入模型
from model import Goods, Supplier
 
supplier_list = [
    {
    "name": "淘宝",
    "address": "杭州",
    "phone": "15548452158"
    },
    {
    "name": "天猫",
    "address": "杭州",
    "phone": "15422584552"
    },
    {
    "name": "京东",
    "address": "北京",
    "phone": "15424896324"
    },
    {
    "name": "蘑菇街",
    "address": "上海",
    "phone": "15545221485"
    }
]
 
goods_list = [
    {
        "name": "护舒宝",
        "click_num": 100,
        "goods_num": 666,
        "price": 10,
        "brief": "防侧漏",
        "supplier": 1,
    },
    {
        "name": "苏菲",
        "click_num": 120,
        "goods_num": 874,
        "price": 8,
        "brief": "双面侧翼,安心无忧",
        "supplier": 2,
    },
    {
        "name": "毓婷",
        "click_num": 60,
        "goods_num": 541,
        "price": 30,
        "brief": "有毓婷,放心爱",
        "supplier": 3
 
},
    {
        "name": "冈本001",
        "click_num": 5800,
        "goods_num": 1500,
        "price": 60,
        "brief": "冈本超薄,给您最极致的体验",
        "supplier": 4
 
}
]
 
 
def save_model():
    # 添加单个元素直接这样添加即可, 然后使用save保存
    '''
    supplier = Supplier()
    supplier.name = "淘宝"
    supplier.address = "杭州"
    supplier.phone = "15841259841"
 
    supplier.save()
    '''
 
    # 添加多个元素的话
    for data in supplier_list:
        supplier = Supplier()
        supplier.name = data["name"]
        supplier.address = data["address"]
        supplier.phone = data["phone"]
 
        supplier.save()
 
    for data in goods_list:
        '''
        也可以这样添加
        goods = Goods(name=data["name"], click_num=data["click_num"], goods_num=data["goods_num"], price=data["price"], brief=data"brief"])
        '''
        # data里的key要和Goods模型定义的列名保持一致
        goods = Goods(**data)
        goods.save()
 
 
if __name__ == '__main__':
    save_model()

orm之peewee

peewee查询数据

from model import Goods
import peewee
 
 
# 获取某条数据,可以通过get方式查询,模型里面虽然没有定义id,但是表里面有,这个查找会映射到表里面去查找
good1 = Goods.get(Goods.id == 1)
# 虽然显示的是1,因为我们是按照id查找的,所以默认显示id
print(good1)  # 1
# 但其实是一个<Model: Goods>
print(type(good1))  # <Model: Goods>
# 可以用这个good1查找其它属性
print(good1.name, " T_T ", good1.brief)  # 护舒宝  T_T  防侧漏
 
# 同理也可以根据其它字段查询
good2 = Goods.get(Goods.name == "冈本001")
print(good2.brief)  # 冈本超薄,给您最极致的体验
 
# 如果是通过id获取的话,那么有两个专门的方式
good3 = Goods.get_by_id(2)
print(good3)  # 2
print(good3.name, " --- ", good3.brief)  # 苏菲  ---  双面侧翼,安心无忧
# 还可以像列表一样传值,但是里面的值并不是索引,而是id
good4 = Goods[3]
print(good4, type(good4))  # 3 <Model: Goods>
print(good4.name, " --- ", good4.brief)  # 毓婷  ---  有毓婷,放心爱
'''
为什么可以使用Goods[3]这种方式,看一下源码,会发现peewee.Model继承的父类有这么一段
    def __getitem__(self, key):
        return self.get_by_id(key)
实际上是实现了__getitem__这个魔法方法,而底层还是使用了get_by_id
'''
 
# 获取所有数据
'''
这句话等价于select * from goods,但是这是一个懒执行,类似于spark里面的transform,或者python里面的迭代器
像get,get_by_id等方法,使用之后会立即组成sql语句然后去查询,但是select返回的是<class 'peewee.ModelSelect'>这个类
会组成sql语句,但不会立即执行,而是当我们使用for循环迭代的时候,才会执行.
如何实现,实际上是底层实现了迭代协议
'''
good5 = Goods.select()
for good in good5:
    # 即便在循环的时候,打印good默认还是打印id
    print(good, type(good), good.name, good.click_num, good.brief)
    '''
    1 <Model: Goods> 护舒宝 100 防侧漏
    2 <Model: Goods> 苏菲 120 双面侧翼,安心无忧
    3 <Model: Goods> 毓婷 60 有毓婷,放心爱
    4 <Model: Goods> 冈本001 5800 冈本超薄,给您最极致的体验
    '''
# 此外如果我们想看执行的sql语句,可以使用good5.sql()进行查看
print(good5.sql())  # ('SELECT `t1`.`id`, `t1`.`name`, `t1`.`click_num`, `t1`.`goods_num`, `t1`.`price`, `t1`.`brief`, `t1`.`supplier_id` FROM `goods` AS `t1`', [])
# 关于select,如果我们不想选择所有的字段呢?那么可以传入想获取的字段名
good6 = Goods.select(Goods.name, Goods.price)
for good in good6:
    # good虽然是<Model: Goods>,但是打印good默认还是打印id,但是我们查询的没有id只有name和price。
    # 因此good为None,good.brief也为None
    print(good, good.name, good.price, good.brief)
    '''
    None 护舒宝 10.0 None
    None 苏菲 8.0 None
    None 毓婷 30.0 None
    None 冈本001 60.0 None
    '''
 
# 根据条件获取
# select * from goods where price > 8.0
good7 = Goods.select().where(Goods.price > 8.0)
for good in good7:
    print(good.name)
    '''
    护舒宝
    毓婷
    冈本001
    '''
# select * from goods where price > 8.0 and price < 60.0 ,同理or的话就用|
good8 = Goods.select().where((Goods.price > 8.0) & (Goods.price < 60.0))
for good in good8:
    print(good.name)
    '''
    护舒宝
    毓婷
    '''
# select * from goods where name is like "%宝"
good9 = Goods.select().where(Goods.name.contains("宝"))
'''
也可以这么写
good9 = Goods.select().where(Goods.name % "%宝")
'''
for good in good9:
    print(good.name)
    '''
    护舒宝
    '''
# 同理Goods.name.startswith和Goods.name.endswith也是支持的
# select * from goods where id in (1, 3)
good10 = Goods.select().where(Goods.id.in_([1, 3]))  # 这里可以用in_,也可以用<<
'''
good10 = Goods.select().where(Goods.id << [1, 3])
'''
for good in good10:
    print(good.name, good)
    '''
    护舒宝 1
    毓婷 3
    '''
# select * from goods where id between 1 and 3
good11 = Goods.select().where(Goods.id.between(1, 3))
for good in good11:
    print(good.name, good.id)
    '''
    护舒宝 1  
    苏菲 2
    毓婷 3
    '''
 
# 还可以使用正则,注意这里的正则是mysql里面的正则,不是python里面的正则
'''
^a:以a开头的字符
a$:以a结尾的字符
.:匹配除了\n之外的任意字符
[....]:匹配包含在[....]里面的字符
[^....]:匹配不包含在[....]里面的字符
a|b|c:匹配a或b或c
*:重复零次或多次
?:重复零次或一次
+:重复一次或多次
需要注意:
1.like和regexp不要混用,like模式不支持正则,正则也不认识_,%
2.mysql里的正则没有贪婪非、贪婪匹配啥的
3.这里是mysql的正则,不是python的正则,所以不要出现\d,\w之类的
'''
good12 = Goods.select().where(Goods.name.regexp(r"宝$"))
for good in good12:
    print(good, good.name)
    '''
    1 护舒宝
    '''
# 忽略大小写,由于是中文,因此结果是一样的
good13 = Goods.select().where(Goods.name.iregexp(r"宝$"))
for good in good13:
    print(good, good.name)
    '''
    1 护舒宝
    '''
 
# 选出click_num大于goods_num的
good14 = Goods.select().where(Goods.click_num > Goods.goods_num)
for good in good14:
    print(good.click_num, good.goods_num, good.name)
    '''
    5800 1500 冈本001
    '''
 
# 选出click_num小于goods_num的
good14 = Goods.select().where(Goods.click_num < Goods.goods_num)
for good in good14:
    print(good.click_num, good.goods_num, good.name)
    '''
    100 666 护舒宝
    120 874 苏菲
    60 541 毓婷
    '''
 
# 排序
# select * from goods order by click_num desc
good15 = Goods.select().order_by(Goods.click_num.desc())  # 同理还有升序asc, 如果是输入字段名那么默认升序
for good in good15:
    print(good.name, good.click_num)
    '''
    冈本001 5800
    苏菲 120
    护舒宝 100
    毓婷 60
    '''
# 这个orm是仿照Django的,而且Django支持使用+表示升序,-表示降序
good16 = Goods.select().order_by(+Goods.click_num)
for good in good16:
    print(good.click_num, good.name)
    '''
    60 毓婷
    100 护舒宝
    120 苏菲
    5800 冈本001
    '''
good17 = Goods.select().order_by(-Goods.click_num)
for good in good17:
    print(good.click_num, good.name)
    '''
    5800 冈本001
    120 苏菲
    100 护舒宝
    60 毓婷
    '''
 
# 使用count查询表*有多少条数据
good18 = Goods.select().count()
print(good18)
 
# 分组,聚合
'''
from peewee import fn
fn.COUNT
fn.SUM
'''
 
# 分页
# 表示从第二行开始取两行数据,索引是从零开始的
good19 = Goods.select().group_by(Goods.price).paginate(1, 2)
for good in good19:
    print(good.name, good.price)
    '''
    苏菲 8.0
    护舒宝 10.0
    '''

peewee更新数据和删除数据

from model import Goods
 
good1 = Goods.get_by_id(1)
print(good1.name, good1.price)  # 护舒宝 10.0
# 获取id=1的记录,就像添加数据一样进行修改.
good1.price = 11.0
good1.save()
print(good1.name, good1.price)  # 护舒宝 11.0
 
# 数据修改还可以使用update
good2 = Goods.get_by_id(4)
print(good2.name)  # 冈本001
# 注意:update里面不需要模型了,直接输入字段名就可以了,因为在where中已经知道表名了
# 必须要execute才会生效
Goods.update(name="冈本002").where(Goods.id == 4).execute()
print(Goods.get_by_id(4).name)  # 冈本002
# 但是
print(Goods.get_by_id(4).price)  # 60.0
# 如果是这样更新的话, 右边必须加上模型名,否则报错
Goods.update(price=Goods.price+10).where(Goods.id == 4).execute()
print(Goods.get_by_id(4).price)  # 70.0
 
 
# 删除一条记录
good3 = Goods.get_by_id(2)
# 这样获取到的id=2的记录便被删除了
good3.delete_instance()
try:  # select方法,如果没数据,那么为空,但是get或者get_by_id如果获取不到数据会抛异常,GOODS.DoseNotExist
    Goods.get_by_id(2)
except Exception:
    import traceback
    print(traceback.format_exc())
    '''
Traceback (most recent call last):
  File "D:/龙卷风/chapter1/update_delete_data.py", line 29, in <module>
    Goods.get_by_id(2)
  File "C:\python37\lib\site-packages\peewee.py", line 5629, in get_by_id
    return cls.get(cls._meta.primary_key == pk)
  File "C:\python37\lib\site-packages\peewee.py", line 5618, in get
    return sq.get()
  File "C:\python37\lib\site-packages\peewee.py", line 6021, in get
    (clone.model, sql, params))
model.GoodsDoesNotExist: <Model: Goods> instance matching query does not exist:
SQL: SELECT `t1`.`id`, `t1`.`name`, `t1`.`click_num`, `t1`.`goods_num`, `t1`.`price`, `t1`.`brief`, `t1`.`supplier_id` FROM `goods` AS `t1` WHERE (`t1`.`id` = %s) LIMIT %s OFFSET %s
Params: [2, 1, 0]
    '''
# delete from goods where price > 0.0
# 这个同样需要execute,否则是不会执行的,这下估计会把数据全部清空
Goods.delete().where(Goods.price > 0.0).execute()

orm之peewee

上一篇:python – KeyError:Flask_security中的’security’?


下一篇:python – 在Peewee中允许空值