在使用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 会自动在相关的模型中添加一个属性,让使用者能够轻松地访问另一侧的对象。这样可以避免手动创建额外的属性或查询语句。

在上述示例中,studentsclassroom 就是使用 backref 创建的反向引用属性。在 Class 模型中,使用了 students = db.relationship('Student', backref='classroom', lazy=True),这会在 Class 对象中创建一个名为 students 的属性,通过该属性可以访问与该班级关联的所有学生对象。

backref 与 ForeignKey

backrefForeignKey 通常是配合使用的,尤其是在定义模型之间的关系时。它们分别用于创建双向关联以及指定外键关系。

  • 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)