在使用Flask框架对关系型数据库进行操作是,使用Flask-SQLAlchemy进行ORM是比较常见的。这里就做一个笔记来描述一对一 一对多 多对多的定义方法。
以常用的学生管理模型为例,定义一下三个模型
学生Student
班级Class
课程Course
其中
- 班级与学生是一对多关系
- 学生与班级是一对一关系
- 学生与课程是多对多关系
代码实现
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///students.db' # 使用SQLite作为数据库
db = SQLAlchemy(app)
# 班级模型
class Class(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(50), nullable=False)
students = db.relationship('Student', backref='classroom', lazy=True)
# 学生模型
class Student(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(50), nullable=False)
class_id = db.Column(db.Integer, db.ForeignKey('class.id'), nullable=False)
courses = db.relationship('Course', secondary='student_course', back_populates='students')
# 课程模型
class Course(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(50), nullable=False)
students = db.relationship('Student', secondary='student_course', back_populates='courses')
# 学生和课程之间的关联表
student_course = db.Table('student_course',
db.Column('student_id', db.Integer, db.ForeignKey('student.id'), primary_key=True),
db.Column('course_id', db.Integer, db.ForeignKey('course.id'), primary_key=True)
)
if __name__ == '__main__':
db.create_all() # 创建数据库表格
app.run(debug=True)
在上述代码中,我们定义了三个模型类:Class、Student 和 Course。它们分别表示班级、学生和课程。Class 和 Student 之间是一对多关系,使用了外键来建立关联。Student 和 Course 之间是多对多关系,使用了中间关联表 student_course。
关于backref
在一个模型中使用 backref
参数来定义一个关系时,Flask-SQLAlchemy 会自动在相关的模型中添加一个属性,让使用者能够轻松地访问另一侧的对象。这样可以避免手动创建额外的属性或查询语句。
在上述示例中,students
和 classroom
就是使用 backref
创建的反向引用属性。在 Class
模型中,使用了 students = db.relationship('Student', backref='classroom', lazy=True)
,这会在 Class
对象中创建一个名为 students
的属性,通过该属性可以访问与该班级关联的所有学生对象。
backref 与 ForeignKey
backref
和 ForeignKey
通常是配合使用的,尤其是在定义模型之间的关系时。它们分别用于创建双向关联以及指定外键关系。
ForeignKey
: 在定义一对多或多对一的关系时,你需要使用ForeignKey
字段来指定外键。这个外键将连接两个相关的表,以建立关系。例如,在示例中,Student
模型中的class_id = db.Column(db.Integer, db.ForeignKey('class.id'), nullable=False)
就是用来定义学生和班级之间的外键关系。backref
:backref
参数用于在一对多关系中创建一个反向引用属性,从而能够从一侧的对象直接访问与之关联的多个对象。在示例中,Class
模型中的students = db.relationship('Student', backref='classroom', lazy=True)
就是用来创建一个名为students
的反向引用属性,可以通过它来访问与该班级相关的所有学生。
这两者的结合使用可以使模型之间的关系更加清晰和方便。ForeignKey
用于建立数据库层面的关系,而 backref
则用于在应用代码中更容易地操作这些关系。
多对多模型
在上文中学生与可成的多对多关联表使用直接定义方式
# 学生和课程之间的关联表
student_course = db.Table('student_course',
db.Column('student_id', db.Integer, db.ForeignKey('student.id'), primary_key=True),
db.Column('course_id', db.Integer, db.ForeignKey('course.id'), primary_key=True)
)
如果觉得不由统一,可以使用改用模型类形式编写。不过,看起来有些更复杂
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///students.db'
db = SQLAlchemy(app)
class Class(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(50), nullable=False)
students = db.relationship('Student', backref='classroom', lazy=True)
class Student(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(50), nullable=False)
class_id = db.Column(db.Integer, db.ForeignKey('class.id'), nullable=False)
student_courses = db.relationship('StudentCourse', back_populates='student')
class Course(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(50), nullable=False)
student_courses = db.relationship('StudentCourse', back_populates='course')
class StudentCourse(db.Model):
student_id = db.Column(db.Integer, db.ForeignKey('student.id'), primary_key=True)
course_id = db.Column(db.Integer, db.ForeignKey('course.id'), primary_key=True)
student = db.relationship('Student', back_populates='student_courses')
course = db.relationship('Course', back_populates='student_courses')
if __name__ == '__main__':
db.create_all()
app.run(debug=True)