基于案例全面理解Flask ORM CRUD

341 阅读5分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 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操作了,记住,关联实际业务理解和练习,对于这类型的知识点效果是最好的。