1、安装
pip install peewee
2、基础:
初始化数据库:
db = MySQLDatabase('database_name', user='www-data', charset='utf8mb4')
创建model:
class BaseModel(Model):
class Meta:
database = db
class User(BaseModel):
name = CharField(unique = True)
age = IntegerField()
sex = CharField()
迁移模型(也叫生成表):
db.connect()
User.create_table() # 也可以使用 db.create_tables([User]),但是建议使用前者迁移模型
db.close()
3、字段类型
以下字段类型对象与之对应的是MySQL中的数据类型
需要对比其他数据库的可以参考官方文档Peewee文档
AutoField:integer
UUIDField:varchar(40)
CharField:varchar
IntegerField:integer
DecimalField:numeric
TextField:text
DateTimeField:datetime
DateField:date
TimeField:time
FixedCharField:char
BigAutoField:bigint
BigIntegerField:bigint
SmallIntegerField:smallint
IdentityField:not supported
FloatField:real
DoubleField:double precision
BlobField:blob
BitField:bigint
BigBitField:blob
BinaryUUIDField:varbinary(16)
TimestampField:integer
IPField:bigint
BooleanField:bool
BareField:not supported
ForeignKeyField:integer
ManyToManyField:无
这些字段常用的基本参数,下面的都是默认设置,实际中根据需求修改:
null = False 是否允许空字符串。
index = False 是否创建普通索引。
unique = False 是否创建唯一索引。
column_name = None 在数据库中指定列的名称,一般不设置会使用定义model时的变量名作为列名。
default = None 设置默认值。
primary_key = False 是否为主键。
constraints = None 增加约束,如果增加,该值是一个列表。
collation = None 用于排序字段或索引的排序规则。
choices = None 设置可选的枚举选项,和Django的ORM射着一样,值是一个元组,元素也是一个元组,例如((1,'女'),(2,'男'))。
help_text = None 设置备注或注释文本。
verbose_name = None 设置一个可读性良好的名称,例如 name = CharField(verbose_name = '用户名')。
index_type = None 指定索引类型,不常用,一般默认即可。
常用字段类型的特殊参数:
CharField、FixedCharField:
max_length = 32 设置给字段最大长度为32,注意CharField的最大max_length=255。
DateTimeField、DateField、TimeField:
formats = '%Y-%m-%d %H:%M:%S' 设置日期时间的格式化,最常用的格式化。
formats = '%Y-%m-%d' 设置日期的格式化,最常用的格式化。
DecimalField:
max_digits = 15 设置要存储的最大位数。
decimal_places = 2 设置最大精度。
auto_round = True 设置自动舍入值。
ForeignKeyField:
model = Model object 这是要引用的model或者外键指向的model,必填。
field = Field 设置外键指向model的具体字段,默认是主键,无特殊需求不用更改,默认即可。
backref = 'str' 设置反向引用的访问器名称,类似于Django中设置外键字段是配置的related_name。
on_delete = 'CASCADE' 设置当被引用的记录删除时,指向该记录的数据操作,存在多个可选值:
CASCADE 跟随外键一同删除
RESTRICT 限制外表中的数据删除,就是当外键删除时,检测到有指向该外键的数据,那么就不允许删除。
SET NULL 设置空值
SET DEFAULT 设置默认值
NO ACTION 不做操作,默认的
on_update = 'CASCADE' 和on_delete作用类似,只是on_update实在外键数据修改时触发。
ManyToManyField:对于这个字段,由于peewee支持的不是很好,建议需要多对多model设计时,使用ForeignKeyField建立第三方表实现。
model = Model object 这是要引用的model或者外键指向的model,必填。
backref = 'str' 设置反向引用的访问器名称,类似于Django中设置外键字段是配置的related_name。
on_delete = 'CASCADE' 设置当被引用的记录删除时,指向该记录的数据操作,存在多个可选值:
CASCADE 跟随外键一同删除
RESTRICT 限制外表中的数据删除,就是当外键删除时,检测到有指向该外键的数据,那么就不允许删除。
SET NULL 设置空值
SET DEFAULT 设置默认值
NO ACTION 不做操作,默认的
on_update = 'CASCADE' 和on_delete作用类似,只是on_update实在外键数据修改时触发。
模型选项和表元数据 - class Meta的设置:
database 设置模型使用的数据库,可以通过继承设置。也就意味着我们可以写一个基本的model,然后其他model都继承自这个基本model。
示例:
class UserModel(Model):
name = CharField(unique = True)
age = IntegerField()
sex = CharField()
class Meta:
database = MySQLDatabase('my_database')
table_name 设置表名,不可以通过继承设置。如果不想使用默认值,每个model在编写时需要手动设置。
示例:
class UserModel(Model):
name = CharField(unique = True)
age = IntegerField()
sex = CharField()
class Meta:
table_name = 'user_table'
table_function 可以设置一个函数用来动态生成表名的功能。可以通过继承设置。
示例:
def make_table_name(model_class):
model_name = model_class.__name__
return model_name.lower() + '_tbl'
class BaseModel(Model):
class Meta:
table_function = make_table_name
class User(BaseModel):
# table_name will be "user_tbl".
class UserProfile(BaseModel):
# table_name will be "userprofile_tbl".
indexes 设置要索引的字段列表,可以设置联合索引,类似Django的联合索引设置。可以通过继承设置。
class Transaction(Model):
from_acct = CharField()
to_acct = CharField()
amount = DecimalField()
date = DateTimeField()
class Meta:
indexes = (
# create a unique on from/to/date
(('from_acct', 'to_acct', 'date'), True),
# create a non-unique on from/to
(('from_acct', 'to_acct'), False),
)
primary_key 设置复合主键。可以通过继承设置。
示例:
class BlogToTag(Model):
"""A simple "through" table for many-to-many relationship."""
blog = ForeignKeyField(Blog)
tag = ForeignKeyField(Tag)
class Meta:
primary_key = CompositeKey('blog', 'tag')
constraints 设置表约束列表。可以通过继承设置。
示例:
class Person(Model):
first = CharField()
last = CharField()
class Meta:
primary_key = CompositeKey('first', 'last')
class Pet(Model):
owner_first = CharField()
owner_last = CharField()
pet_name = CharField()
class Meta:
constraints = [SQL('FOREIGN KEY(owner_first, owner_last) '
'REFERENCES person(first, last)')]
4、基于User模型的增删改查:
一:新增
1、create
user = User.create(name='张三',age=26,sex='男') # 创建一个记录,并返回一个user对象
2、save
user = User(name='张三',age=26,sex='男')
user.save() # 创建一个记录,并返回一个user对象
3、insert
user_id = User.insert(name='张三',age=26,sex='男').execute() # 创建一个记录,并返回新纪录的主键
这里使用了 execute() 方法,因为insert不会马上执行,execute()方法可以马上执行操作。
4、insert_many
User.insert_many([
('张三丰', 26, '男'),
('王大胖', 12, '男'),
('王小小', 22, '女')
],
['name', 'age', 'sex']
).execute()
也可以插入字典列表
User.insert_many([
{
'name': 王二小', 'age': 12, 'sex': '男'},
{
'name': 王小小', 'age': 13, 'sex': '女'},
{
'name': 王大胖', 'age': 15, 'sex': '男'}
]).execute()
5、bulk_create
和Django类似的批量创建
users = [
{
'name': 王二小', 'age': 12, 'sex': '男'},
{
'name': 王小小', 'age': 13, 'sex': '女'},
{
'name': 王大胖', 'age': 15, 'sex': '男'}
]
datas = [User(**item) for item in users]
# 不使用事务
User.bulk_create(datas)
# 使用事务
with db.atomic():
User.bulk_create(datas)
二、查询
1、get 和 get_or_none
user = User.get(User.id==1) # 当获取的结果不存在时,报 Model.DoesNotExist 异常。如果有多条记录满足条件,返回第一条。
user = User.get_or_none(User.id==1) # 和get的区别是,当没有匹配数据时返回None,不会抛出异常。
2、get_by_id
user = User.get_by_id(1) # 对于主键查找可以用这个
3、get_or_create
user, created = User.get_or_create(name='张三', defaults={
'age': 26, 'sex': '男'}) # 如果存在就返回user,不存在就创建后再返回user
4、select
使用 Model.select() 查询获取多条数据。select 后可以添加 where 条件,如果不加则查询所有数据。
user = User.select() # 查询user内的所有数据,查询所有列
user = User.select(User.id, User.name) # 查询列为id、name,返回所有数据
带where条件的:
where语句中查询运算符:
## 与或非逻辑运算符:
& 与 示例:(User.is_active == True) & (User.is_admin == True)
| 或 示例:(User.is_admin) | (User.is_superuser)
~ 非 示例:~(User.username.contains('admin'))
比较运算符:
== 等于
< 小于
<= 小等于
> 大于
>= 大等于
!= 不等于
<< x IN y,其中y是列表或查询
>> x IS y,其中y可以是None / NULL,例如判断obj_id >> None 相当于SQL语句:obj_id is NULL
% x喜欢y,其中y可能包含通配符
** x像y,其中y可能包含通配符
^ 异或
~ 一元否定(例如,NOT x)
## 和MySQL查询的一些运算符:
.in_(value) IN查找(与相同<<)。
.not_in(value) 不在查询中。
.is_null(is_null) IS NULL或IS NOT NULL。接受布尔参数。
.contains(substr) 通配符搜索子字符串。相当于 LIKE '%xx%'
.startswith(prefix) 搜索以开头的值prefix。
.endswith(suffix) 搜索以结尾的值suffix。
.between(low, high) 在low和之间搜索值high。
.regexp(exp) 正则表达式匹配(区分大小写)。
.iregexp(exp) 正则表达式匹配(不区分大小写)。
.bin_and(value) 二进制AND。
.bin_or(value) 二进制或。
.concat(other) 使用串联两个字符串或对象||。
.distinct() 标记列以进行DISTINCT选择。
.collate(collation) 用给定的排序规则指定列。
.cast(type) 将列的值强制转换为给定的类型。
示例:
user = User.select().where(User.name == '张三') # 查询所有叫张三的数据
user = User.select().where(User.name == '张三', User.age = 26) # 查询名字叫张三并且年龄为26的数据
user = User.select().where((User.name == '张三') | (User.age = 26)) # 查询名字叫张三或者年龄为26的数据
user = User.select().where(~User.age == 26)# 查询年龄不等于26的数据
user = User.select().where(User.age != 26)# 查询年龄不等于26的数据
user = User.select().where(User.age >= 26)# 查询年龄大等于26的数据
user = User.select().where(User.age in [24,26,27]) # 查询年龄在[24,26,27]内的数据
user = User.select().where(User.name.contains('张三')) # 模糊查询,相当于 LIKE '%张三%'
排序:
user = User.select().order_by(User.id) # 默认升序 == order_by(User.id.asc())
user = User.select().order_by(-User.id) # 降序排序 == order_by(User.id.desc())
取出前N个数据:
user = User.select().order_by(-User.id).limit(10) # 取出id从大到小的前10个数据
计数count:
tatol = User.select().count() # 统计所有数据条数
分页查询:
user = User.select().order_by(User.id).paginate(2, 10) # paginate(page, page_size) 查出第二页,每页10条数据
分组聚合查询:
query = User.select(User.age, fn.Count(User.id).alias('count')).group_by(User.age)
假设现在有三个表分别为:
class Photo(Model):
image = CharField()
class Tag(Model):
name = CharField()
class PhotoTag(Model):
photo = ForeignKeyField(Photo)
tag = ForeignKeyField(Tag)
query = (Tag.select().join(PhotoTag).join(Photo).group_by(Tag).having(fn.Count(Photo.id) > 5))
三、修改
1、save
user = User.get(User.id==1)
user.age = 18
user.save()
2、update
user = User.update(age=18).where(User.name=='张三').execute() # update用于批量更新,将所有匹配结果进行更新
User.update(age=User.age + 1).execute() # 批量操作,会将所有人的年龄加一后再储存
四、删除
1、delete
User.delete().where(User.id == 1).execute() # 可以应用批量删除
User.delete().where(User.age < 18).execute() # 可以删除所有年龄小于18的数据行
2、delete_instance
user = User.get(User.id=1) # 针对已经知道明确的对象时,可以应用该删除方法更好些,可以避免误删。
user.delete_instance()
使用事务:使用事务可以保证原子性等事务的四大特性
with db.atomic():
# 执行相关SQL操作
user = User.get(User.id=1)
user.age = 18
user.save()