开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第9天,点击查看活动详情
之前完成了ORM数据库建模,那么基于ORM来看看数据库的操作吧。
以学员,课程,教室为例,先确定一下三个模型直接关系:
1、一个学员有一个教室多个课程;
2、一个课程可以有过个学员学习;
3、一个教室可以有过个学员;
所以,
学员和教室是多对一
学员和课程是多对多
数据模型如下:
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
#配置数据库
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+pymysql://root:@127.0.0.1:3306/test'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
app.config['SQLALCHEMY_ECHO'] = True
db = SQLAlchemy(app)
#创建数据表映射
student_course = db.Table(
'student_course',
db.Column('student_id', db.Integer, db.ForeignKey('student.id')), #注意这里用的使用表名.id不是类名.id
db.Column('course_id', db.Integer, db.ForeignKey('course.id'))
)
class ClassRoom(db.Model):
__tablename__ = "class_room"
id = db.Column(db.Integer, primary_key = True)
class_number = db.Column(db.String(10))
students = db.relationship('Student', backref='student_room')
class Course(db.Model):
__tablename__ = "course"
id = db.Column(db.Integer, primary_key=True)
course_name = db.Column(db.String(32))
class Student(db.Model):
__tablename__ = "student"
id = db.Column(db.Integer, primary_key = True)
student_name = db.Column(db.String(32))
age = db.Column(db.Integer)
class_room = db.Column(db.Integer, db.ForeignKey(ClassRoom.id))
courses = db.relationship('Course',secondary=student_course,backref=db.backref('students'))
if __name__ == "__main__":
with app.app_context():
db.create_all() #同步数据库
app.run()
增
添加数据在数据库当中采用的是insert数据,但是在orm当中采用的是数据库映射,所以,变成了基于ORM类的操作。流程如下:
新增课程
course = Course()
course.course_name = "Python"
db.session.add(course)
db.session.commit()
新增教室
class_room = ClassRoom()
class_room.class_number = "1-301"
db.session.add(class_room)
db.session.commit()
新增学生
student = Student()
student.student_name = "张三"
student.age = 18
db.session.add(student)
db.session.commit()
学员新增教室,需要使用教室的id就可以了
class_room = ClassRoom.query.get(1)
student = Student()
student.student_name = "李四"
student.age = 17
student.class_room = class_room.id
db.session.add(student)
db.session.commit()
也可以通过反向映射来增加教室
class_room = ClassRoom.query.get(1)
student = Student()
student.student_name = "王五"
student.age = 13
student.student_room = class_room
db.session.add(student)
db.session.commit()
注意:这里的student_room就是在类ClassRoom当中设置的反向映射字段students = db.relationship('Student', backref='student_room' )
也可以通过教室来新增学员,
class_room = ClassRoom.query.get(1)
student = Student.query.get(1)
class_room.students.append(student)
db.session.add(class_room)
db.session.commit()
新增学生与课程的关联,这个和新增课程是一个样的
#学员新增课程
student = Student.query.get(1)
course = Course.query.get(1)
student.courses.append(course)
db.session.add(student)
db.session.commit()
#课程新增学员
student = Student.query.get(1)
course = Course.query.get(1)
course.students.append(student) #也是通过反向映射来的
db.session.add(course)
db.session.commit()
注意:
1、反向映射是ORM的特性,不会作用到数据库当中,所以修改不会对数据库字段产生影响。
2、上面的新增分为两种,在新增数据的时候绑定相关联表数据,还有获取已有数据绑定关联,二者是类似的。
查
说完增加啊数据,那么来聊聊查询,查询应该是ORM操作最多的一个方面,我们进行细分:
这里需要提前注意的是,查询返回的结果并不直接是数据,而是orm类的实例,还需要进行实例.字段才可以获取到数据。
查询单条数据
flask-sqlalchemy提供了get方法来查询单条数据,但是有所局限的是:
1、get只能指定一个字段作为查询条件,默认是id
2、get如果查询不到会返回None,那么下面连续取值的语句就会报错
student = Student.query.get(1)
print(student.student_name)
flask-sqlalchemy也提供了first,last方法获取多条查询当中的第一条或者最后一条数据,所以一般不是使用id进行单挑查询多使用的是多条查询结合first或者last方法:
student = Student.query.filter_by(age=18).first()
print(student.student_name)
查询所有数据
flask使用all方法查询所有数据,这里注意,除了查询单挑数据的方法,其他方法返回的是数组结构,需要循环获取内容。
students = Student.query.all()
print([student.student_name for student in students])
排序查询
from sqlalchemy import desc
students = Student.query.order_by("id") #正序
students_reverse = Student.query.order_by(desc("id")) #倒序
print([student.student_name for student in students])
print([student.student_name for student in students_reverse])
条件查询
条件查询分为两种,filter_by查询,可以直接进行赋值查询,将字段作为属性,查询字段等于的值,filter则需要调用orm模型,但是可以进行复杂的逻辑运算查询。
filter_by查询数据
查询:查询所有年龄等于18的学员
students = Student.query.filter_by(age = 18)
print([student.student_name for student in students])
filter查询数据
查询:查询所有年龄大于18的学员
students = Student.query.filter(Student.age >= 18)
print([student.student_name for student in students])
注意:
1、filter和filter_by都可以不传递参数来查询所有数据
2、filter当中的等于是 ==
范围查询数据
和sql一样,flask-sqlalchemy同样使用limit和offset来进行范围查询
查询:从第2条数据开始查1条学员信息
students = Student.query.limit(1).offset(2)
print([student.student_name for student in students])
模糊查询数据
和sql一样,flask-sqlalchemy同样使用like进行模糊查询
查询:查询所有姓李的学员
students = Student.query.filter(Student.student_name.like("李%"))
print([student.student_name for student in students])
聚合查询数据
和sql一样,flask-sqlalchemy同样具有 count,sum,max,min,avg这样的聚合函数,但是需要借助sqlalchemy.sql下的func来调用
查询:查询所有学员的平均年龄
from sqlalchemy.sql import func
students = Student.query.with_entities(func.avg(Student.age)).all()
print(students)
分组查询数据
和sql一样,flask-sqlalchemy同样使用group_by进行分组查询
查询:通过姓名进行分组查询每个分组学员的平均年龄
from sqlalchemy.sql import func
students = Student.query.with_entities(func.avg(Student.age)).group_by(Student.student_name).all()
print(students)
逻辑查询数据
通常的条件查询语句都是and并列关系,flask-sqlalchemy也提供了其他的逻辑关系词:
查询所有名字叫李四或者年龄18岁的学员
from sqlalchemy import or_, and_, not_
students = Student.query.filter(or_(Student.student_name=="李四",Student.age==18))
print([student.student_name for student in students])
and_ not_用法相同
关系表查询
flask-sqlalchemy 关系表查询查询一直遵循有关联字段使用字段,没有关联字段使用反向映射字段的规则:
1、查询id为1的学员的课程
student = Student.query.get(1)
print(student.courses)
2、查询学习id为1的课程的学员
course = Course.query.get(1)
print(course.students)
这里的studnets来自于学员表当中的反向映射字段:courses = db.relationship('Course',secondary=student_course,backref=db.backref('students') )反向映射。
3、查询id为1的学员的教室
student = Student.query.get(1)
print(student.student_room)
这里直接使用外键字段class_room只会得到教室的id,获得完整的教室信息需要使用定义在教室类当中的反向映射字段:students = db.relationship('Student', backref='student_room' )
4、查询id为1的班级的所有教室
class_room = ClassRoom.query.get(1)
print(class_room.students)
改
修改和新增数据的操作相当类似,别就是修改数据需要先查询出指定的数据,并且不需要从新add数据实例,然后进行修改。
student = Student.query.get(3)
student.student_name = "李三"
db.session.commit()
删
删除数据应该是最简单的操作了
student = Student.query.get(4)
db.session.delete(student)
db.session.commit()
上面就是常用的ORM数据库CRUD操作了,记住,关联实际业务理解和练习,对于这类型的知识点效果是最好的。