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])
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()
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()