peewee操作mysql的增删改查

前言

推荐查看官方文档:https://www.osgeo.cn/peewee/
安装peewee

pip3 install peewee

• 在学习peewee之前先了解下ORM(Object Relational Mapping)对象关系映射,解决面向对象与关系数据库不匹配的技术。

peewee 是什么?

• peewee是一种轻量级的python ORM
• 可以理解为MongoDB与NoSQL的关系
• 在学习peewee时,发现其中大量使用了内部类,就重新补充了一下关于内部类的知识点
• 关于使用内部类的优势
• 内部类可以有多个实例,每个实例都有自己的状态信息,并且与其外围类对象那个的信息相互独立;
• 在单个外围类中,可以让多个内部类以不同的方式实现同一个接口,或继承同一个类;
• 创建内部类对象的时刻并不依赖于外围类对象的创建;
• 内部类并没有令人迷惑的“is-a”关系,它就是一个独立的实体。
• 安装mysql
• 从官网安装最新版本
• 注意的是安装完成后需要修改密码才能进行外部连接

常用操作

操作解释
Db.is_closed()判断数据库是不是连接
Db.connect()连接数据库
Db.create_tables([Person,])建表
Person.create_tables()建表(Person是一个类名)

关于主键和约束 #都是在类的内部类中定义

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

插入数据
P=Person.create(name=’name’,sex=’sex’);
p.save();
或者使用
Person.insert(name=’name’,sex=’sex’).execute();
关于从一个表查数据快速插到另一个表 还需再思考下
修改数据
Tweet.update(message='这是修改过的数据').where(Tweet.id==3).execute();
注意的是,在peewee中条件中使用‘==’。更新的数据不用加类名,但是条件中的字段必须加类名。
数据删除
Tweet.update(message='这是修改过的数据3').where(Tweet.id==3).execute();
数据查询
User.get(id=1);#一条
User.get_by_id(1);
ts=Tweet.filter(user_id=1);#所有迭代器
注意:使用get()并且没有参数返回的是查询的id
复合查询
q=User.select().where((User.id==1)|(User.username=='tom')).get();
q=User.select().where((User.id==1)&(User.username=='tom')).get();
模糊查询
#select * from Tweet where message like ’%数据%’;
print(Tweet.select().where(Tweet.message ** "%数据%").get());
print(Tweet.select().where(Tweet.message.contains('数据')).get());
in 查询
print(Tweet.select().where(Tweet.id.in_([1, 2])).get());


Order by; Limit; Distinct; Group by; Having


query = (Person.select(Person.name).order_by(Person.name).limit(10).distinct())  # 几乎和sql一模一样
Person.select().order_by(Person.birthday.desc())  # 日期排序
query = (Booking
         .select(Booking.facid, fn.SUM(Booking.slots)) 
         .group_by(Booking.facid)   # group_by
         .order_by(Booking.facid))
query = (Booking
         .select(Booking.facility, fn.SUM(Booking.slots))
         .group_by(Booking.facility)
         .having(fn.SUM(Booking.slots) > 1000)   # having
         .order_by(Booking.facility))
Tweet.select().order_by(-Tweet.created_date)




# 返回查到了多少条记录
Tweet.select().where(Tweet.id > 50).count()
连表查询
g1 = Person.select().join(Pet).where(Pet.name == "dog2")


实例讲解
参考(https://www.cnblogs.com/fnng/p/6879779.html)

#!/usr/bin/env python3
#-*- coding:utf-8 -*-
from peewee import *;
import datetime;
#建立连接mysql时的必要参数
db = MySQLDatabase('peewee_learn',host ='127.0.0.1',user='root',passwd='123456');
#连接数据库
db.connect();
class BaseModel(Model):
	#内部类
	class Meta:
		database=db;#每一个继承BaseModel类的子类都是连接db表
class User(BaseModel):
	username=CharField(unique=True);#每个属性都是一个表字段
class Tweet(BaseModel):
	user = ForeignKeyField(User,related_name='tweets');
	message = TextField();
	created_date = DateTimeField(default=datetime.datetime.now);
	is_published = BooleanField(default=True);
if __name__ == '__main__':
	#创建表
	User.create_table();#创建User表
		Tweet.create_table();#创建Tweet表
#插入数据
	#user=User.create(username='tom');
	#Tweet.create(user=user,message='这是一段文字');
	#Tweet.create(user_id=1,message='这是第二段文字');
	#查询数据get()
	#t = Tweet.get(message="这是一段文字")
	#print(t.user_id)
	#print(t.created_date)
	#print(t.is_published)
	#filter
	#ts=Tweet.filter(user_id=1);
	#for t in ts:
#print(t.message);

首先,导入peewee库下面的所有方法,这个当然需要。

然后,通过MySQLDatabase连接数据库,把数据连接的几个必要参数一一填写。通过connect()方法与MySQL数据库建立链接。

接下来就是表的创建,创建BaseModel类,在该类下创建子类Meta,Meta是一个内部类,它用于定义peewee的Model类的行为特性。指定dabatase 为 前面定义的db。

再接下来就是表的创建了,我们在SQL语句创建表时一般需要知道以下信息。表的名字,表有哪些字段?这些字段分别是什么类型?是否允许为空,或自增?哪个字段是主键是?哪个是外键?

ORM用编程语言里的概念帮我们映射了这些东西。

创建 User 和 Tweet类做为表名。在类下面定义的变量为字段名,如username、message、created_date等。通过CharField、DateTimeField、BooleanField表示字段的类型。ForeignKeyField 建立外键。 主键呢? 建表时不都要有个主键id嘛,不用!peewee默认已经为我们加上这个id了。
最后,执行create_table()方法创建两张表。
通过数据库工具,查看生成的两张表。

插入数据
要想操作数据,首先表里需要有数据。先来看看如何添加数据。
if name == “main”:
# …
user = User.create(username=‘tom’)
Tweet.create(user=user, message=“这是一段文字”)

这样就要User表里添加一个tom的用户,这用户发了一条Tweet,在Tweet表里。但这个用户兴致来了,想继续发第二条Tweet。于是:
if name == “main”:
# …
Tweet.create(user_id=1, message=“这是第二段文字”)
咦~!?不对,我们没有创建user_id字段啊!但是,如果你查询Tweet表,就会发现有这个字段,用它来关联User表的id

查询数据
if name == “main”:
# …
# 查询 1
t = Tweet.get(message=“这是一段文字”)
print(t.user_id)
print(t.created_date)
print(t.is_published)
查询结果
1
2017-05-19 15:44:32
True
不过,get()方法只能查询一条,且是唯一的一条数据;通过查询条件不能查询出多条,也不能查询出0条。
if name == “main”:
# …
# 查询 2
ts = Tweet.filter(user_id=1)
for t in ts:
print(t.message)
运行结果
这是一段文字
这是第二段文字
而,filter()方法,就会更加灵活,可以查询多条结果,并把结果循环输出。

删除数据

参考https://www.cnblogs.com/fnng/p/6879779.html

https://www.cnblogs.com/yxi-liu/p/8514763.html

模型定义

模型类,字段和模型实例都映射到数据库的概念:

对象对应于
模型类数据库表
字段实例表上的行
模型实例数据库表中的行

当使用Peewee启动项目时,通常最好从数据模型开始,通过定义一个或多个 Model 类别:

from peewee import *

db = SqliteDatabase('people.db')

class Person(Model):
    name = CharField()
    birthday = DateField()

    class Meta:
        database = db # This model uses the "people.db" database.
注解:
Peewee将自动从类的名称推断数据库表名。您可以通过指定 table_name 内部“meta”类中的属性(
与 database 属性)。要进一步了解peewee如何生成表名,请参阅 表名 部分。

还要注意,我们为模型命名 Person 而不是 People . 这是您应该遵循的一个惯例——即使表将包含多个人,
我们总是使用单数形式命名类。

有很多 field types 适用于存储各种类型的数据。Peewee手柄在 pythonic 值那些数据库使用的值,这样您就可以在代码中使用Python类型,而无需担心。

外键的使用

有很多 field types 适用于存储各种类型的数据。Peewee手柄在 pythonic 值那些数据库使用的值,这样您就可以在代码中使用Python类型,而无需担心。

当我们使用 foreign key relationships . 这对于Peewee很简单:

class Pet(Model):
    owner = ForeignKeyField(Person, backref='pets')
    name = CharField()
    animal_type = CharField()

    class Meta:
        database = db # this model uses the "people.db" database

既然我们有了模型,我们就连接到数据库。尽管不需要显式打开连接,但这是一种好的做法,因为它会立即显示数据库连接中的任何错误,而不是在执行第一个查询之后的某个任意时间。完成连接后关闭连接也很好——例如,Web应用程序可能在收到请求时打开连接,并在发送响应时关闭连接。

db.connect()

我们将首先在数据库中创建存储数据的表。这将创建具有适当列、索引、序列和外键约束的表:

db.create_tables([Person, Pet])

增加数据

让我们先用一些人填充数据库。我们将使用 save() 和 create() 方法添加和更新人员记录。

from datetime import date
uncle_bob = Person(name='Bob',birthday = date(1960,1,15))
uncle_bob.save()# bob is now stored in the database
# Returns: 1
注解:
Returns: 1
当你调用 save() ,返回修改的行数。 

您也可以通过 create() 方法,返回模型实例:

grandma = Person.create(name= 'Grandma', birthday=date(1935,3,1))
herb = Person.create(name='Herb',birthday=date(1950,5,5))

更新数据

要更新行,请修改模型实例并调用 save() 坚持改变。在这里,我们将更改奶奶的姓名,然后将更改保存到数据库中:

grandma.name = 'Grandma L.'
grandma.save()  # Update grandma's name in the database.
# Returns: 1

现在我们在数据库中存储了3个人。让我们给他们一些宠物。奶奶不喜欢家里的动物,所以她没有,但赫伯是个动物爱好者:

bob_kitty = Pet.create(owner=uncle_bob, name='Kitty', animal_type='cat')
herb_fido = Pet.create(owner=herb, name='Fido', animal_type='dog')
herb_mittens = Pet.create(owner=herb, name='Mittens', animal_type='cat')
herb_mittens_jr = Pet.create(owner=herb, name='Mittens Jr', animal_type='cat')

删除数据

在漫长的一生之后,宠物会生病死亡。我们需要将他从数据库中删除:

herb_mittens.delete_instance() # he had a great life
# Returns: 1
注解
的返回值 delete_instance() 是从数据库中删除的行数。

修改数据

鲍勃叔叔认为在赫伯家里有太多动物死亡,所以他收养了fido:

herb_fido.owner = uncle_bob
herb_fido.save()

查询数据

我们数据库的真正优势在于它允许我们通过 查询. 关系数据库非常适合进行即席查询。

查询单个数据

让我们从数据库中检索奶奶的记录。要从数据库中获取单个记录,请使用 Select.get() :
grandma = Person.select().where(Person.name == ‘Grandma L.’).get()

grandma = Person.select().where(Person.name == 'Grandma L.').get()

我们也可以使用等价的速记法 Model.get() :

grandma = Person.get(Person.name == 'Grandma L.')

查询全部数据

让我们列出数据库中的所有人员:

for person in Person.select():
    print(person.name)
-----打印结果如下:---------
# Bob
# Grandma L.
# Herb

让我们列出所有的猫和它们的主人的名字:

query = Pet.select().where(Pet.animal_type == 'cat')
for pet in query:
    print(pet.name, pet.owner.name)
-----打印结果如下:---------
# Kitty Bob
# Mittens Jr Herb
注意
前一个查询有一个大问题:因为我们正在访问 pet.owner.name 我们在原始查询中没有选择这个关系,
Peewee需要执行一个额外的查询来检索宠物的主人。这种行为被称为 N+1 一般应该避免。
有关处理关系和联接的深入指南,请参阅 本人的下一篇
我们可以通过同时选择这两个选项来避免额外的查询 Pet 和 人, 添加一个 join.

我们可以通过同时选择这两个选项来避免额外的查询 Pet 和 人, 添加一个 join.

query = (Pet
         .select(Pet, Person)
         .join(Person)
         .where(Pet.animal_type == 'cat'))

for pet in query:
    print(pet.name, pet.owner.name)
-----打印结果如下:---------
# Kitty Bob
# Mittens Jr Herb 

让我们把鲍勃所有的宠物都买下来:(查询鲍勃的所有宠物)

for pet in Pet.select().join(Person).where(Person.name == 'Bob'):
    print(pet.name)
-----打印结果如下:---------
# Kitty
# Fido

通过模型实例对象来查询鲍勃的所有宠物
我们可以在这里做另一件很酷的事情来得到鲍勃的宠物。因为我们已经有了一个对象来代表Bob,所以我们可以这样做:

for pet in Pet.select().where(Pet.owner == uncle_bob):
    print(pet.name)

分组 order_by( )

for pet in Pet.select().where(Pet.owner == uncle_bob).order_by(Pet.name):
    print(pet.name)
-----打印结果如下:---------
# Fido
# Kitty

现在让我们列出所有人,从最年轻到最年长:

for person in Person.select().order_by(Person.birthday.desc()):#desc()降序方法
    print(person.name, person.birthday)
-----打印结果如下:---------
# Bob 1960-01-15
# Herb 1950-05-05
# Grandma L. 1935-03-01

分组筛选表达式

Peewee支持任意嵌套表达式。让我们查询生日是的人:
1940年以前(奶奶)
1959年以后(鲍勃)

query = (Person
				.select()
				.where(Person.birthday<d1940) | (Person.birthday<d1960))
for person in query:
	print(person.name,person.birthday)
-----打印结果如下:---------
# Bob 1960-01-15
# Grandma L. 1935-03-01

现在让我们做相反的事情。1940年至1960年生日的人:

query = (Person
				.select
				.where(Person.birthday.between(d1940,d1960)))
for person in query:
	print(person.name,person.birthday)
-----打印结果如下:---------
# Herb 1950-05-05

聚合和预取

让我们列出所有人 and 他们有多少宠物:

for person in Person.select():
	print (person.name,person.pets.count(),'pets')
-----打印结果如下:---------
# Bob 2 pets
# Grandma L. 0 pets
# Herb 1 pets

我们又碰到了一个经典的例子 N+1 查询行为。在本例中,我们对 Person 原件返还 SELECT !我们可以通过执行 JOIN 并使用SQL函数聚合结果。
以名字排序查询出每个人有多少只宠物

query = (Person
				.select(Person, fn.COUNT(Pet.id).alias('pet_count')
				.join(Pet,JOIN.LEFT_OUTER)  #包括没有宠物的人
				.group_by(Person)
				.order_by(Person.name))
for person in query:
	print(person.name,person.pet_count,'pets') #pet_count是返回模型实例上的一个属性

fn.COUNT(Pet.id).alias(‘pet_count’) 想当于COUNT(pet.id) AS pet_count .

注解
Peewee提供了一个神奇的助手 fn() ,可用于调用任何SQL函数。在上面的例子中, fn.COUNT(Pet.id).alias('pet_count') 会被翻译成 COUNT(pet.id) AS pet_count . 

现在让我们列出所有的人和他们所有宠物的名字。你可能已经猜到了,这很容易变成另一个 N+1 如果我们不小心的话。

在深入到代码中之前,请考虑这个示例与前面的示例有何不同,我们在这里列出了所有宠物及其所有者的名称。宠物只能有一个主人,所以当我们从 Pet 到 Person 总有一场比赛。我们加入时情况不同 Person 到 Pet 因为一个人可能没有宠物或者他们可能有几个宠物。因为我们使用的是关系数据库,如果我们要从 Person 到 Pet 然后每个有多只宠物的人都会被重复,每只宠物一次。

如下所示:

query = (Person
				.select(Person,Pet)
				.join(Pet,JOIN.LEFT_OUTER)  # 左外连接
				.order_by(Person.name,Pet.name))
# 我们需要检查他们是否有宠物的实例附加属性,不是所有的人们都养猫
for person in query:
	if hasattr(person,"pet"):#hasattr()函数用于判断对象是否包含对应的属性。hasattr(object, name)
		print(person.name,person.pet.name)
	else:
		print(person.name,"no pets")
-----打印结果如下:---------
# Bob Fido
# Bob Kitty
# Grandma L. no pets
# Herb Mittens Jr

通常这种类型的复制是不可取的。以适应更常见(和直观)的工作流,即列出一个人并附加 a list 在那个人的宠物中,我们可以使用一种特殊的方法: prefetch()预取 :

query = Person.select().order_by(Person.name).prefech(Pet)
for person in query:
	print(person.name)
	for pet in person.pets:
		print('	*',pet.name)
-----打印结果如下:---------
# Bob
#   * Kitty
#   * Fido
# Grandma L.
# Herb
#   * Mittens Jr

SQL函数

模糊查询

最后一个查询。这将使用SQL函数查找名称以大写或小写开头的所有人员 G:

expression = fu.Lower(fn.Substr(Person.name,1,1)) == 'g'
for person in Person.select().where(expression):
	print(person.name)
-----打印结果如下:---------
# Grandma L.

数据库

数据库处理完毕,让我们关闭连接:

db.close()

在实际的应用程序中,有一些已建立的模式用于管理数据库连接生存期。例如,Web应用程序通常会在请求开始时打开连接,并在生成响应后关闭连接。A connection pool 有助于消除与启动成本相关的延迟。

使用现有数据库

如果已经有了数据库,可以使用 Pwiz,模型发生器 . 例如,如果我有一个名为 charles_blog, 我可能会跑:

python -m pwiz -e postgresql charles_blog > blog_models.py

总结

#存储数据
##方式一:save()
uncle_bob = Person(name='Bob',birthday = date(1960,1,15))
uncle_bob.save()
模型实例名 =  模型类名(字段实例名1=“字段数据”,字段实例名2=“字段数据”)
模型实例名.save()

##方式二:create()
grandma = Person.create(name='Grandma', birthday=date(1935, 3, 1))
模型实例名 =  模型类.create(字段实例名1=“字段数据”,字段实例名2=“字段数据”)
---------------------------------------------
# 更新
grandma.name = 'Grandma L.'
grandma.save() 
#模型实例名.字段实例名=“新字段数据”
#模型实例名.save()
----------------------------------------------
# 删除
herb_mittens.delete_instance()
#模型实例名.delete_instance()
----------------------------------------------
# 查询
## 查询单个数据
### 方法一:Select.get() 
grandma = Person.select().where(Person.name == 'Grandma L.').get()
#模型实例名 =  模型类.select().where(表名.字段名(列) == ‘字段名数据‘).get()
### 方法二:Model.get()
grandma = Person.get(Person.name == 'Grandma L.')
#模型实例名 =  模型类.get(模型类.字段名(列) == ‘字段名数据‘).get()

## 查询所有数据(列出数据库中的所有人员)
for person in Person.select():
    print(person.name)
#个人总结
for i in 模型类.select():
	print(i.字段名)
# 以上查询的是列中所有数据	

# 查询所有符合条件的数据(列出所有的猫和它们的主人的名字) 方式一:
query = Pet.select().where(Pet.animal_type == 'cat')
for pet in query:
    print(pet.name, pet.owner.name)
#个人总结
query = 模型类.select().where(模型类.查询条件)
for i in query:
	print(i.字段名1,i.外键名.字段名2)
	
# 方式二:我们可以通过同时选择这两个选项来避免额外的查询 Pet 和 人, 添加一个 join.
query = (Pet
         .select(Pet, Person)
         .join(Person)
         .where(Pet.animal_type == 'cat'))

for pet in query:
    print(pet.name, pet.owner.name)

# 个人总结
query = 模型名1.select(模型类1,模型类2).join(模型类2).where(模型类1.查询条件)
for i in query:
	print(i.字段名1,i.外键名.字段名2)

#  查询相关



  • 2
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值