前言:
继续上一章:爬虫之数据神器4---Peewee事务管理和连接池用法-CSDN博客
本章主要就是对peewee的实战进行一些案例的讲解!
正文:
1.模型数据操作
1.1 案例:建立学生和课程模型,实现基本的CRUD
我们先创建Student和Course两个模型,分别表示学生和课程信息。实现基本的CRUD操作,包括:
- 创建Student和Course对象,保存到数据库
- 查询数据库中所有的Student和Course
- 修改Student的部分字段信息
- 删除数据库中的一门Course
代码实现:
from peewee import *db = SqliteDatabase('school.db')class Student(Model):name = CharField()age = IntegerField()class Meta:database = dbclass Course(Model): name = CharField()teacher = CharField()credits = IntegerField()class Meta:database = dbdb.connect()
db.create_tables([Student, Course])# 创建两个模型对象
tom = Student.create(name='Tom', age=18)
python = Course.create(name='Python', teacher='Mr Lee', credits=3)# 查询数据库中的所有Student和Course
for s in Student.select():print(s.name, s.age)for c in Course.select():print(c.name, c.teacher, c.credits)# 修改Student信息
tom.age = 19
tom.save()# 删除一门课程
python.delete_instance()
1.2 案例:添加查询表达式实现学生复杂查询
在查询Student时,我们可以用查询表达式实现更复杂的查询:
- 查询age>20的学生
- 查询name包含'T'的学生
- 查询按age倒序排序的学生
代码实现:
# 查询age > 20的学生
old_students = Student.select().where(Student.age > 20) # 查询name包含'T'的学生
t_students = Student.select().where(Student.name.contains('T'))# 查询按age倒序排序的学生
for s in Student.select().order_by(Student.age.desc()):print(s.name, s.age)
1.3 案例:使用原生SQL进行特定的数据统计
Peewee支持在模型查询中使用原生SQL,实现复杂的统计查询:
- 使用SQL求学生平均年龄
- 使用SQL求每个老师教授课程的数量
代码实现:
# 求学生平均年龄
avg_age = Student.select(fn.AVG(Student.age)).scalar() # 求每个老师教授课程数量
for row in Course.raw('SELECT teacher, COUNT(*) FROM Course GROUP BY teacher'):print(row)
以上通过具体案例使用Peewee实现模型的CRUD、复杂查询和原生SQL,让大家更直观地了解如何操作模型数据。
2.高级查询方法
2.1 案例:使用Q对象实现组合条件查询
在查询时,我们经常需要基于多个条件进行组合查询。直接使用where语句实现会非常麻烦,而Peewee提供的Q对象可以方便地处理这种情况。
Q对象就像一个容器,我们可以将多个查询条件添加到Q对象中,它会自动处理组合的逻辑关系。
例如,查询同时满足name包含'a'和age大于20的学生:
from peewee import *Student = model_defined # 预定义的Student模型query = Student.select()
query.where(Q(Student.name.contains('a')) & Q(Student.age > 20))
这里我们向Q对象中添加了两个条件,它们之间是“与”的逻辑关系。
Q对象也可以包含“或”逻辑:
query = Student.select()
query.where(Q(Student.name.contains('a')) | Q(Student.age > 20))
这样就可以非常灵活地组合查询条件,实现复杂的查询逻辑,而不需要多层嵌套where语句。
2.2 案例:使用prefetch提升学生查询课程的效率
在学生和课程之间是一对多的关系。如果我们需要查询每个学生及他们的所有课程,通常需要两次查询:
for student in Student.select():# 首先查询学生courses = Course.select().where(Course.student == student)# 然后查询每个学生的课程print(student.name, courses)
这样多次查询数据库的效率是非常低下的。
使用prefetch可以通过一次查询就获取学生及课程的信息:
query = Student.select(Student, Course).join(Course, on=(Student.id == Course.student)).prefetch(Course)for student in query:print(student.name)for course in student.courses_set: print(course.name)
prefetch会在查询学生的同时提前预加载课程,这样就避免了多次查询,大幅提升效率。
2.3 案例:对课程进行分组和聚合运算
分组聚合是数据库的重要功能之一。Peewee也提供了便捷的分组和聚合方法:
# 按课程学分分组,统计选课学生数量
query = Course.select(Course, fn.COUNT(Student.id)).join(Student).group_by(Course.credits) for course in query:print(course.credits, course.count) # 计算每个老师的平均课程学分
query = Course.select(Course.teacher, fn.AVG(Course.credits)).group_by(Course.teacher)for course in query:print(course.teacher, course.credits_avg)
以上案例演示了Q对象进行组合查询、prefetch提升关联查询效率以及分组聚合的用法,可以实现更高效和复杂的查询操作。Peewee的高级查询功能可以大幅简化我们的数据库操作,使代码更简洁高效。
通过这些高级功能的使用,可以写出更优雅和Python化的ORM代码,而不需要过多考虑底层SQL语句,这样可以提高我们的开发效率。
3. 模型之间的关联操作
关系数据库的重要特性就是不同数据表之间存在关联。在Peewee中我们也可以进行关联操作。
3.1 案例:实现学生-课程的关联添加课程
学生和课程存在一对多的关系,一个学生可以选择多门课程。我们可以通过关联添加的方式实现一个学生选择课程:
jim = Student.select().where(Student.name=='Jim').get()
math = Course.select().where(Course.name=='Math').get()# 方法1:直接通过关联属性添加
jim.courses.add(math) # 方法2:通过create实现添加
Course.create(student=jim, name='Physics')
添加关联数据只需要简单的一两行代码,就可以实现复杂的关联关系维护。
3.2案例:使用join进行关联模型的查询
我们可以通过join方法进行关联模型的查询:
# 查询每个学生及选修的课程
query = Student.select(Student, Course).join(Course, on=(Student.id == Course.student))for student in query:print(student.name)for course in student.courses_set:print(course.name)
join查询非常适合在一对多关系中查询主模型及其关联记录。这比通过外键进行额外查询更高效。
3.3案例:学生与选课合并保存到数据库
有时候我们需要在代码中构建完整的关联数据,并全部保存到数据库。这时我们可以通过构造模型实例,然后调用insert方法进行合并保存。
jim = Student.create(name='Jim')courses = [Course.create(name='Math'),Course.create(name='Physics'),
]# 方法1:直接保存关联属性
jim.courses = courses
jim.save()# 方法2:使用insert合并保存
data = [(jim, course) for course in courses]
StudentCourse.insert_many(data).execute()
合并保存大大简化了我们构建关联数据的代码。
综上,Peewee通过关联属性、join查询、合并保存等方法简化了关联模型的操作,使我们可以更容易地处理关系数据,减少冗余重复的代码。
好的,我用约3000字,结合案例、代码和说明,用中文详细表达一下“Peewee的事务管理”和“Peewee实践优化”这两个章节的内容:
4. Peewee的事务管理
事务是保证数据操作原子性和一致性的机制。Peewee也提供了事务管理功能。
4.1 案例:使用事务实现学生选课的原子性操作
学生选课需要插入多条关联数据,这是一个典型需要事务的场景:
courses = [Course.get(1), Course.get(2), Course.get(3)] try:with db.atomic(): for course in courses:StudentCourse.create(student=student, course=course)
except Exception:# 如果有任何异常,自动回滚事务print("Error selecting courses")
通过atomic可以确保这些插入要么全部成功,要么全部失败,保证了选课操作的原子性。
4.2案例:事务嵌套示范
Peewee支持事务的嵌套,内层事务会自动合并到外层事务中:
with db.atomic() as outer:StudentCourse.create(student=1, course=1)with db.atomic() as inner:StudentCourse.create(student=1, course=2)StudentCourse.create(student=1, course=3)# 内外事务会合并,所有创建作为一个事务执行
嵌套事务可以在保持原子性的同时,按业务逻辑对数据操作进行分组。
5. Peewee实践优化
通过一些优化手段,可以大大提升Peewee的实际应用效率。
5.1案例:对模型进行字段优化
增加字段选项可以优化模型性能:
class Student(Model):name = CharField(max_length=50, index=True) age = IntegerField(null=True)class Meta:table_name = 'students'
name字段增加索引,age字段允许为空。表名自定义为students。
5.2 案例:添加索引提高查询性能
我们可以直接通过代码添加索引:
# 为name字段添加索引
Student.add_index(Student.name)# 为复合条件添加索引
Student.add_index(Student.age, Student.name)
索引可以大幅提升过滤和排序的查询速度。
5.3 案例:使用惰性加载提升大批量查询
惰性加载可以避免大量未使用的数据被加载:
#只查询id, 不加载其他字段
query = Student.select(Student.id).lazy() for id in query:# 根据id加载其他字段student = Student.get_by_id(id)
惰性加载减少内存占用,特别适合大规模数据的查询。
以上是通过对模型、索引和查询进行优化,来提高Peewee实际应用性能的方法,可以大幅减少程序的执行时间。
总结:
这篇文章通过丰富的案例,全面介绍了Python ORM框架Peewee的高级用法。
- 文章首先介绍了模型的CRUD操作,以及使用查询表达式实现复杂查询的方法。
- 然后讲解了Peewee的高级查询功能,如使用Q对象进行组合查询,使用prefetch提高关联查询效率等。
- 接着文章讲解了模型之间的关联操作,讲解非常透彻。
- 最后两章讲解了Peewee的事务管理以及优化手段。
----比如使用Q对象和prefetch可以写出更优雅高效的代码,事务可以保证数据操作的原子性,添加索引、优化字段等可以提升实际效率。Peewee通过简单易用的API把数据库的复杂操作封装起来,我们只需要学习这些高级功能就可以游刃有余地操作数据库了。虽然SQL也很强大,但ORM的优势在于对数据库的抽象封装,专注业务而不是底层SQL。