Flask Models进阶 多表
'''
多表查询时,db.relationship在哪边,哪边就是正向
正向查找 关联关系名
反向查找 backref
# 班级表
class Grade(db.Model):
__tablename__ = 'grade' # 表名
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
name = db.Column(db.String(30), unique=True)
student = db.relationship('Student', backref='grade', lazy=True)
# 学生表
class Student(db.Model):
__tablename__ = 'student'
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
name = db.Column(db.String(30), unique=True)
age = db.Column(db.Integer)
# 外键 跟Grade表中的id字段关联
gradeid = db.Column(db.Integer, db.ForeignKey(Grade.id))
如 班级和学生 db.relationship在班级表中
班级表去查学生 就是正向查找 Grade.query.get(1).student 就能拿到班级id为1的所有的学生
学生表去查班级 就是反向查找 Student.query.get(1).grade 就能获取到该学生所在的班级的数据对象 Student.query.get(1).grade.name就可以获取班级的名称
注意:
要和django的orm区分开,django中外键字段在的一边是正向
正向查找 外键字段
反向查找 表名小写 + _set
'''
一对一关系
一对多关系
'''
注意 外键建在多的一边 学生多所以外键在学生表
'''
案例
# 多表关系
# 一对多
# 班级:学生 = 1:N
# 班级表
class Grade(db.Model):
__tablename__ = 'grade' # 表名
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
name = db.Column(db.String(30), unique=True)
# 建立关联
# 第一个参数:关联的模型名(表)
# 第二个参数:反向引用的名称,让student去反过来得到grade对象的名称 student.grade
# 第三个参数:懒加载
# 这里的student不是字段,
student = db.relationship('Student', backref='grade', lazy=True)
# 第一个参数关联哪张表,第二个参数:反向查找是用的关键字,第三个参数:懒加载
# 学生表
class Student(db.Model):
__tablename__ = 'student'
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
name = db.Column(db.String(30), unique=True)
age = db.Column(db.Integer)
# 外键 跟Grade表中的id字段关联
gradeid = db.Column(db.Integer, db.ForeignKey(Grade.id))
# 一对多
# 增加数据
@blueprints1.route('/addgrade/')
def add_grade():
# 添加班级
grades = []
for i in range(10):
grades.append(Grade(name='LCX' + str(i)))
try:
db.session.add_all(grades)
db.session.commit()
except Exception as e:
print(e)
db.session.rollback()
db.session.flush()
return e
return 'OK!'
@blueprints1.route('/addstu/')
def add_stu():
# 添加学生
students = []
for i in range(10):
students.append(Student(name='kunkun{}'.format(i), age=i, gradeid=random.randint(1, 3)))
try:
db.session.add_all(students)
db.session.commit()
except Exception as e:
print(e)
db.session.rollback()
db.session.flush()
return e
return 'OK!'
# 修改
# 这里就展示学生的修改,班级的修改是一样的
@blueprints1.route('/updatestu/')
def update_stu():
stu = Student.query.first()
stu.age = 100
db.session.commit()
return 'OK!'
# 删除学生
@blueprints1.route('/delstu/')
def del_stu():
stu = Student.query.first()
db.session.delete(stu)
db.session.commit()
return 'OK!'
# 删除班级
@blueprints1.route('/delgrade/')
def del_grade():
'''
删除班级后,对应的班级里的学生的外键字段会变成空(null)
'''
grade = Grade.query.first()
db.session.delete(grade)
db.session.commit()
return 'OK!'
# 查询
@blueprints1.route('/getstu/')
def get_stu():
# 查询某个学生所在的班级 如id为3的学生所在的班级
stu = Student.query.get(3)
print(stu.name, stu.age, stu.gradeid, stu.grade)
# kunkun2 2 3 <Grade 3>
print(stu.grade.id, stu.grade.name)
# 3 LCX2
# 查询某个班级下的所有学生 如班级id为2下的所有学生
grade = Grade.query.get(2)
print(grade.name) # LCX1
print(grade.student) # 所有学生 里面的是学生对象,可以用for循环得到每一个学生对象
# [<Student 4>, <Student 5>, <Student 6>, <Student 7>, <Student 9>, <Student 10>]
for stud in grade.student:
print(stud.name)
return 'OK!'
多对多
案例
# 多对多
# 用户收藏电影
# 用户 : 电影 = N : M
# 中间表(第三张表)最好是写在另外2张表的上面: 收藏表
collects = db.Table(
'collects', # 第三张表的名称
db.Column('userid', db.Integer, db.ForeignKey('usermodel.id'), primary_key=True),
# 第一个参数:字段名,第二个参数:字段类型,第三个参数:外键关联(使用表名小写.id的形式),第四个参数:设为主键
db.Column('movie', db.Integer, db.ForeignKey('movie.id'), primary_key=True),
)
# 用户表
class UserModel(db.Model):
__tablename__ = 'usermodel'
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
name = db.Column(db.String(30))
age = db.Column(db.Integer)
# 电影表
class Movie(db.Model):
__tablename__ = 'movie'
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
name = db.Column(db.String(30))
# 关联关系
# secondary = collect 设置中间表
usermodel = db.relationship('UserModel', backref='movies', lazy='dynamic', secondary=collects)
# 第一个参数关联哪张表,第二个参数:反向查找是用的关键字,第三个参数:懒加载
'''
lazy属性:
懒加载,可以延迟在使用关联属性的时候才建立关联 (建立关联时需要消耗资源,懒加载防止了一直消耗资源)
lazy= 'dynamic ':会返回一个query对象(查询集),可以继续使用其他查询方法,如all().
lazy='select':首次访问到属性的时候,就会全部加载该属性的数据.
lazy='joined ':在对关联的两个表进行join操作,从而获取到所有相关的对象
lazy=T&ue:返回一个可用的列表对象,同select
'''
1.准备数据
# 添加用户数据
@blueprints1.route('/addusers/')
def add_users():
users = []
for i in range(10):
users.append(UserModel(name='kunkun' + str(i), age=i))
try:
db.session.add_all(users)
db.session.commit()
except:
db.session.rollback()
db.session.flush()
return 'OK!'
# 添加电影数据
@blueprints1.route('/addmovie/')
def add_movies():
movies = []
for i in range(4):
movies.append(Movie(name='电影' + str(i)))
try:
db.session.add_all(movies)
db.session.commit()
except:
db.session.rollback()
db.session.flush()
return 'OK!'
2.添加第三张表的关联关系记录
@blueprints1.route('/addcollect/')
def add_collect():
# 用户收藏电影
user = UserModel.query.get(1)
movie = Movie.query.get(1)
user.movies.append(movie)
db.session.commit()
return 'OK!'
3.修改第三张表的记录
@blueprints1.route('/updatecollect/')
def update_collect():
# 用户id为2的用户取消收藏电影id为3的电影
user = UserModel.query.get(2)
movie = Movie.query.get(3)
user.movies.remove(movie)
db.session.commit()
return 'OK!'
4.删除用户(删除多对多的任意一张表都是一样的)
@blueprints1.route('/deluser/')
def del_user():
'''
删除后,第三张表中对应的userid为1的记录会被删除,不会像一对多那样设置为null
'''
# 级联删除
user = UserModel.query.get(1)
db.session.delete(user)
db.session.commit()
return 'OK!'
5.查询(最重要的)
@blueprints1.route('/getcollect/')
def get_collect():
# 查找某一个用户收藏的所有电影
user = UserModel.query.get(1)
# 反向查找 (正反看db.relationship ,db.relationship在的一边为正向,db.relationship在Moive表,所有为反向查找,反向查找backref)
print(user.movies) # [<Movie 1>, <Movie 2>, <Movie 3>]
# 查找收藏了某个电影的所有用户
movie = Movie.query.get(3)
print(movie.usermodel) # 正向查找(关联关系名) ,获得到的是一个查询集对象,在db.relationship中的lazy设置了dynamic,所以movie.usermodel还可以继续使用filter过滤等操作
# SELECT usermodel.id AS usermodel_id, usermodel.name AS usermodel_name, usermodel.age AS usermodel_age FROM usermodel, collects WHERE ? = collects.movie AND usermodel.id = collects.userid
print(list(movie.usermodel))
return 'OK!'