在项目开发过程中,会遇到很多数据之间多对多关系的情况,比如:
- 学生网上选课(学生和课程)
- 老师与其授课的班级(老师和班级)
- 用户与其收藏的新闻(用户和新闻)
- 等等…
所以在开发过程中需要使用 ORM 模型将表与表的多对多关联关系使用代码描述出来。多对多关系描述有一个唯一的点就是:需要添加一张单独的表去记录两张表之间的对应关系
需求分析
- 学生可以网上选课,学生有多个,课程也有多个
- 学生有:张三、李四、王五
- 课程有:物理、化学、生物
选修关系有:
- 张三选修了化学和生物
- 李四选修了化学
- 王五选修了物理、化学和生物
需求:
- 查询某个学生选修了哪些课程
- 查询某个课程都有哪些学生选择
思路分析
- 用一张表来保存所有的学生数据
- 用一张表来保存所有的课程数据
- 用一张中间表表示学生与课程的对应关系
结构图如下:
course_student.py
"""
多对多关系
案例: 学生和课程
"""
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
# 1.设置数据库的配置信息
app.config["SQLALCHEMY_DATABASE_URI"] = "mysql+pymysql://root:123456@localhost:3306/test"
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
# 2.创建Sqlalchemy对象,关联app
db = SQLAlchemy(app)
# 3.编写模型类
# 中间表
tb_student_course = db.Table(
"tb_student_course",
db.Column("student_id", db.Integer, db.ForeignKey("students.id")),
db.Column("course_id", db.Integer, db.ForeignKey("courses.id"))
)
# 学生
class Student(db.Model):
__tablename__ = "students"
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
name = db.Column(db.String(32))
# 关系属性secondary: 使用在多对多种,用来表示二次查询的
courses = db.relationship("Course", backref="students", secondary="tb_student_course")
# 为了方便输出对象查看,重写__repr__方法
def __repr__(self):
return "<Student:%s>" % self.name
# 课程
class Course(db.Model):
__tablename__ = "courses"
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
name = db.Column(db.String(32))
# 为了方便输出对象查看,重写__repr__方法
def __repr__(self):
return "<Student:%s>" % self.name
@app.route('/')
def hello_world():
return "helloworld"
if __name__ == '__main__':
# 为了演示方便,先删除,后创建
db.drop_all()
db.create_all()
# 添加测试数据
stu1 = Student(name='张三')
stu2 = Student(name='李四')
stu3 = Student(name='王五')
cou1 = Course(name='物理')
cou2 = Course(name='化学')
cou3 = Course(name='生物')
stu1.courses = [cou2, cou3]
stu2.courses = [cou2]
stu3.courses = [cou1, cou2, cou3]
db.session.add_all([stu1, stu2, stu2])
db.session.add_all([cou1, cou2, cou3])
db.session.commit()
app.run(debug=True)
测试:
In [1]: from course_student import *
In [2]: stu=Student.query.get(1)
In [3]: stu
Out[3]: <Student:张三>
In [4]: stu.courses
Out[4]: [<Student:化学>, <Student:生物>]
In [5]: course=Course.query.get(1)
In [6]: course
Out[6]: <Student:化学>
In [7]: course.students
Out[7]: [<Student:张三>, <Student:李四>, <Student:王五>]