说明 | |
---|---|
backref | 在关系的另一模型中添加反向引用,用于设置外键名称,在1查多的 |
primary join | 明确指定两个模型之间使用的连表条件 |
lazy | 指定如何加载关联模型数据的方式。参数值: select(立即加载,查询所有相关数据显示,相当于lazy=True) subquery(立即加载,但使用子查询) dynamic(不加载记录,但提供加载记录的查询对象) |
uselist | 如果为False,不使用列表,而使用标量值。 一对一关系中,需要设置relationship中的uselist=Flase,其他数据库操作一样。 |
secondary | 指定多对多关系中关系表的名字。 多对多关系中,需建立关系表,设置 secondary=关系表 |
secondary join | 在SQLAlchemy中无法自行决定时,指定多对多关系中的二级连表条件 |
第一范式: 即表的列的具有原子性,不可再分解,即列的信息,不能分解, 只有数据库是关系型数据库(mysql/oracle/db2/informix/sysbase/sql server),就自动的满足1NF
第二范式: 表中的记录是唯一的, 就满足2NF, 通常我们设计一个主键来实现
1对1:把主表的主键放到附加表中作为外键存在。 1对多:把主表(1) 的主键放到附加表(多)作为外键存在。 多对多:把主表(多)的主键和附加表的(多)主键,放到第三方表(关系表)中作为外键。
2.1 模型关联用法
关联属性定义在主模型中
class Student(db.Model): """个人信息主表""" .... # 模型属性,不是数据库的字段,不会在数据表中出现,仅仅是SQLAlchemy为了方便开发者使用关联查询所提供的对象属性 # 因为StudentInfo和Student是一对一的关系,所以uselist=False表示关联一个数据 info = db.relationship("StudentInfo", uselist=False,backref="student") class StudentInfo(db.Model): """个人信息附加表""" # 外键, # 如果是一对一,则外键放在附加表对应的模型中 # 如果是一对多,则外键放在多的表对象的模型中 user_id = db.Column(db.ForeignKey("db_students.id"), comment="学生id")
关联属性定义在模型中外键模型中
class Student(db.Model): """个人信息主表""" .... from sqlalchemy.orm import backref class StudentInfo(db.Model): """个人信息附加表""" # 外键, # 如果是一对一,则外键放在附加表对应的模型中 # 如果是一对多,则外键放在多的表对象的模型中 user_id = db.Column(db.ForeignKey("db_students.id"), comment="学生id") # 因为StudentInfo和Student是一对一的关系,所以uselist=False表示关联一个数据 student = db.relationship("Student", backref=backref("info",uselist=False))
2.2 连表后的增改查
关联属性定义在主模型中
1 from flask import Flask,render_template,request 2 from flask_sqlalchemy import SQLAlchemy 3 4 app = Flask(__name__) 5 6 class Config(object): 7 DEBUG = True 8 # 数据库连接配置 9 # SQLALCHEMY_DATABASE_URI = "数据库类型://数据库账号:密码@数据库地址:端口/数据库名称?charset=utf8mb4" 10 SQLALCHEMY_DATABASE_URI = "mysql://root:123@127.0.0.1:3306/students?charset=utf8mb4" 11 # 动态追踪修改设置,如未设置只会提示警告 12 SQLALCHEMY_TRACK_MODIFICATIONS = True 13 # 查询时会显示原始SQL语句 14 SQLALCHEMY_ECHO = True 15 16 app.config.from_object(Config) 17 18 19 """模型类定义""" 20 db = SQLAlchemy(app=app) 21 # 等同于 22 # db = SQLAlchemy() 23 # db.init_app(app) 24 25 class Student(db.Model): 26 """学生信息模型""" 27 # 声明与当前模型绑定的数据表名称 28 __tablename__ = "db_students" 29 # 字段定义 30 """ 31 create table db_student( 32 id int primary key auto_increment comment="主键", 33 name varchar(15) comment="姓名", 34 ) 35 """ 36 id = db.Column(db.Integer, primary_key=True,comment="主键") 37 name = db.Column(db.String(15), comment="姓名") 38 age = db.Column(db.SmallInteger, comment="年龄") 39 sex = db.Column(db.Boolean, default=True, comment="性别") 40 email = db.Column(db.String(128), comment="邮箱地址") 41 money = db.Column(db.Numeric(10,2), default=0.0, comment="钱包") 42 # 模型属性,不是数据库的字段,不会在数据表中出现,仅仅是SQLAlchemy为了方便开发者使用关联查询所提供的对象属性 43 # info 可以代表与当前数据对应的外键模型对象 44 info = db.relationship("StudentInfo", uselist=False,backref="student") 45 46 def __repr__(self): 47 return f"{self.name}<Student>" 48 49 @classmethod 50 def add(cls): 51 student = cls(name="小明", sex=True, age=17, email="123456@qq.com", money=100) 52 db.session.add(student) 53 db.session.commit() 54 return student 55 56 @property 57 def to_dict(self): 58 """把对象转化成字典""" 59 return { 60 "id": self.id, 61 "name": self.name, 62 "age": self.age, 63 "sex": self.sex, 64 "email": self.email, 65 "money": float("%.2f" % self.money), 66 } 67 68 class StudentInfo(db.Model): 69 """学生信息附加表""" 70 __tablename__ = "db_student_info" 71 id = db.Column(db.Integer, primary_key=True, comment="主键") 72 address = db.Column(db.String(500), nullable=True, comment="地址") 73 qq_num = db.Column(db.String(15), nullable=True, comment="QQ号") 74 # 外键设置[默认创建数据库物理外键] 75 user_id = db.Column(db.ForeignKey("db_students.id"), comment="学生id") 76 77 @app.route("/") 78 def index(): 79 """添加数据""" 80 # 添加主表信息的时候通过关联属性db.relationship同步添加附件表信息 81 # student = Student( 82 # name="xiaolan02", 83 # age=16, 84 # sex=False, 85 # money=10000, 86 # email="xiaolan02@qq.com", 87 # info = StudentInfo(address="北京市昌平区百沙路204号", qq_num="100861000") 88 # ) 89 # db.session.add(student) 90 # db.session.commit() 91 92 # 添加附加表数据,通过关联属性中db.relationshop的backref同步添加主表数据 93 # info = StudentInfo( 94 # address="北京市昌平区百沙路204号", 95 # qq_num="100861220", 96 # student = Student( 97 # name="xiaolan02", 98 # age=16, 99 # sex=False, 100 # money=10000, 101 # email="xiaolan02@qq.com", 102 # ) 103 # ) 104 # 105 # db.session.add(info) 106 # db.session.commit() 107 108 """查询数据""" 109 # 正向关联----> 从主模型查询外键模型 110 # student = Student.query.get(1) 111 # print(student.info) # <StudentInfo 1> 112 # print(student.info.address) # 北京市昌平区百沙路204号 113 # 114 # # 反向关联----> 从外键模型查询主模型 115 # student_info = StudentInfo.query.filter(StudentInfo.qq_num=="100861220").first() 116 # print(student_info.student) # xiaolan02<Student> 117 # print(student_info.student.name) # xiaolan02 118 # print(student_info.user_id) # 2 仅仅获取了外键真实数据 119 120 """修改数据""" 121 # 通过主表使用关联属性可以修改附加表的数据 122 student = Student.query.get(2) 123 student.info.address = "广州市天河区天河东路103号" 124 db.session.commit() 125 126 # 也可以通过附加表模型直接修改主表的数据 127 student_info = StudentInfo.query.filter(StudentInfo.qq_num == "100861220").first() 128 print(student_info.student) 129 student_info.student.age = 22 130 db.session.commit() 131 132 return "ok" 133 134 if __name__ == '__main__': 135 with app.app_context(): 136 # 检测数据库中是否存在和模型匹配的数据表。 137 # 如果没有,则根据模型转换的建表语句进行建表。 138 # 如果找到,则不会进行额外处理 139 140 db.create_all() 141 app.run(debug=True)
关联属性定义在模型中外键模型中
1 from flask import Flask,render_template,request 2 from flask_sqlalchemy import SQLAlchemy 3 4 app = Flask(__name__) 5 6 class Config(object): 7 DEBUG = True 8 # 数据库连接配置 9 # SQLALCHEMY_DATABASE_URI = "数据库类型://数据库账号:密码@数据库地址:端口/数据库名称?charset=utf8mb4" 10 SQLALCHEMY_DATABASE_URI = "mysql://root:123@127.0.0.1:3306/students?charset=utf8mb4" 11 # 动态追踪修改设置,如未设置只会提示警告 12 SQLALCHEMY_TRACK_MODIFICATIONS = True 13 # 查询时会显示原始SQL语句 14 SQLALCHEMY_ECHO = True 15 16 app.config.from_object(Config) 17 18 19 """模型类定义""" 20 db = SQLAlchemy(app=app) 21 # 等同于 22 # db = SQLAlchemy() 23 # db.init_app(app) 24 25 class Student(db.Model): 26 """学生信息模型""" 27 # 声明与当前模型绑定的数据表名称 28 __tablename__ = "db_students" 29 # 字段定义 30 """ 31 create table db_student( 32 id int primary key auto_increment comment="主键", 33 name varchar(15) comment="姓名", 34 ) 35 """ 36 id = db.Column(db.Integer, primary_key=True,comment="主键") 37 name = db.Column(db.String(15), comment="姓名") 38 age = db.Column(db.SmallInteger, comment="年龄") 39 sex = db.Column(db.Boolean, default=True, comment="性别") 40 email = db.Column(db.String(128), comment="邮箱地址") 41 money = db.Column(db.Numeric(10,2), default=0.0, comment="钱包") 42 43 def __repr__(self): 44 return f"{self.name}<Student>" 45 46 @classmethod 47 def add(cls): 48 student = cls(name="小明", sex=True, age=17, email="123456@qq.com", money=100) 49 db.session.add(student) 50 db.session.commit() 51 return student 52 53 @property 54 def to_dict(self): 55 """把对象转化成字典""" 56 return { 57 "id": self.id, 58 "name": self.name, 59 "age": self.age, 60 "sex": self.sex, 61 "email": self.email, 62 "money": float("%.2f" % self.money), 63 } 64 65 from sqlalchemy.orm import backref 66 class StudentInfo(db.Model): 67 """学生信息附加表""" 68 __tablename__ = "db_student_info" 69 id = db.Column(db.Integer, primary_key=True, comment="主键") 70 address = db.Column(db.String(500), nullable=True, comment="地址") 71 qq_num = db.Column(db.String(15), nullable=True, comment="QQ号") 72 # 外键设置[默认创建数据库物理外键] 73 user_id = db.Column(db.ForeignKey("db_students.id"), comment="学生id") 74 # 模型属性,不是数据库的字段,不会在数据表中出现,仅仅是SQLAlchemy为了方便开发者使用关联查询所提供的对象属性 75 # info 可以代表与当前数据对应的外键模型对象 76 student = db.relationship("Student", backref=backref("info",uselist=False)) 77 78 @app.route("/") 79 def index(): 80 """查询数据""" 81 # 正向关联----> 从主模型查询外键模型 82 student_info = StudentInfo.query.filter(StudentInfo.qq_num=="100861220").first() 83 print(student_info.student) # xiaolan02<Student> 84 print(student_info.student.name) # xiaolan02 85 print(student_info.user_id) # 2 仅仅获取了外键真实数据 86 87 88 # 反向关联----> 从外键模型查询主模型 89 student = Student.query.get(1) 90 print(student.info) # <StudentInfo 1> 91 print(student.info.address) # 北京市昌平区百沙路204号 92 93 """修改数据""" 94 # 通过主表使用关联属性可以修改附加表的数据 95 # student = Student.query.get(2) 96 # student.info.address = "广州市天河区天河东路103号" 97 # db.session.commit() 98 99 # 也可以通过附加表模型直接修改主表的数据 100 # student_info = StudentInfo.query.filter(StudentInfo.qq_num == "100861220").first() 101 # print(student_info.student) 102 # student_info.student.age = 22 103 # db.session.commit() 104 105 return "ok" 106 107 if __name__ == '__main__': 108 with app.app_context(): 109 # 检测数据库中是否存在和模型匹配的数据表。 110 # 如果没有,则根据模型转换的建表语句进行建表。 111 # 如果找到,则不会进行额外处理 112 113 db.create_all() 114 app.run(debug=True)
3.1 模型关联用法
class Student(db.Model): ... # 从Student 查询 StudentAddress: Student.address_list = [] # 从StudentAddress 查询 Student: StudentAddress.student = 学生模型对象 address_list = db.relationship("StudentAddress", uselist=True, backref="student") class StudentAddress(db.Model): ... # 外键,多的一方模型中添加外间 user_id = db.Column(db.ForeignKey("db_students.id"), comment="学生id")
关联属性定义在模型中外键模型中
from sqlalchemy.orm import backref
class Student(db.Model): ... class StudentAddress(db.Model): ... # 外键,多的一方模型中添加外间 user_id = db.Column(db.ForeignKey("db_students.id"), comment="学生id") student = db.relationship("Student", uselist=False, backref=backref("address_list",uselist=True))
3.2 连表后的增改查
关联属性定义在主模型中
1 from flask import Flask,render_template,request 2 from flask_sqlalchemy import SQLAlchemy 3 4 app = Flask(__name__) 5 6 class Config(object): 7 DEBUG = True 8 # 数据库连接配置 9 # SQLALCHEMY_DATABASE_URI = "数据库类型://数据库账号:密码@数据库地址:端口/数据库名称?charset=utf8mb4" 10 SQLALCHEMY_DATABASE_URI = "mysql://root:123@127.0.0.1:3306/students?charset=utf8mb4" 11 # 动态追踪修改设置,如未设置只会提示警告 12 SQLALCHEMY_TRACK_MODIFICATIONS = True 13 # 查询时会显示原始SQL语句 14 SQLALCHEMY_ECHO = True 15 16 app.config.from_object(Config) 17 18 19 """模型类定义""" 20 db = SQLAlchemy(app=app) 21 # 等同于 22 # db = SQLAlchemy() 23 # db.init_app(app) 24 25 class Student(db.Model): 26 """学生信息模型""" 27 # 声明与当前模型绑定的数据表名称 28 __tablename__ = "db_students" 29 id = db.Column(db.Integer, primary_key=True,comment="主键") 30 name = db.Column(db.String(15), comment="姓名") 31 age = db.Column(db.SmallInteger, comment="年龄") 32 sex = db.Column(db.Boolean, default=True, comment="性别") 33 email = db.Column(db.String(128), comment="邮箱地址") 34 money = db.Column(db.Numeric(10,2), default=0.0, comment="钱包") 35 # 从Student 查询 StudentAddress: Student.address_list = [] 36 # 从StudentAddress 查询 Student: StudentAddress.student = 学生模型对象 37 address_list = db.relationship("StudentAddress", uselist=True, backref="student") 38 39 def __repr__(self): 40 return f"{self.name}<Student>" 41 42 from sqlalchemy.orm import backref 43 class StudentInfo(db.Model): 44 """学生信息附加表""" 45 __tablename__ = "db_student_info" 46 id = db.Column(db.Integer, primary_key=True, comment="主键") 47 address = db.Column(db.String(500), nullable=True, comment="默认地址") 48 qq_num = db.Column(db.String(15), nullable=True, comment="QQ号") 49 # 外键设置[默认创建数据库物理外键] 50 user_id = db.Column(db.ForeignKey("db_students.id"), comment="学生id") 51 # 模型属性,不是数据库的字段,不会在数据表中出现,仅仅是SQLAlchemy为了方便开发者使用关联查询所提供的对象属性 52 # info 可以代表与当前数据对应的外键模型对象 53 student = db.relationship("Student", backref=backref("info",uselist=False)) 54 55 class StudentAddress(db.Model): 56 """学生收货地址""" 57 __tablename__ = "db_student_address" 58 id = db.Column(db.Integer, primary_key=True, comment="主键") 59 user_id = db.Column(db.ForeignKey("db_students.id"), comment="学生id") 60 province = db.Column(db.String(20), comment="省份") 61 city = db.Column(db.String(20), comment="城市") 62 area = db.Column(db.String(20), comment="地区") 63 address = db.Column(db.String(250), comment="详细接地") 64 # 也可以在外键模型中声明关系熟悉 65 # student = db.relationship("Student", uselist=False, backref=backref("address_list",uselist=True)) 66 67 def __repr__(self): 68 return f"{self.province}-{self.city}-{self.area}-{self.address}" 69 70 @app.route("/") 71 def index(): 72 """添加数据""" 73 # 添加主表信息的时候通过关联属性db.relationship同步添加附件表信息 74 student = Student( 75 name="xiaohei", 76 age=18, 77 sex=False, 78 money=12000, 79 email="xiaohei@qq.com", 80 address_list = [ 81 StudentAddress(province="北京市", city="北京市", area="昌平区", address="百沙路204号"), 82 StudentAddress(province="北京市", city="北京市", area="昌平区", address="百沙路205号"), 83 ], 84 ) 85 db.session.add(student) 86 db.session.commit() 87 88 # 添加附加表数据,通过关联属性中db.relationshop的backref同步添加主表数据 89 # 1. 主模型没创建的情况 90 stu_address = StudentAddress( 91 province="北京市", 92 city="北京市", 93 area="昌平区", 94 address="百沙路206号", 95 student=Student(name="xiaobai",age=18,sex=False,money=12000,email="xiaobai@qq.com",) 96 ) 97 db.session.add(stu_address) 98 db.session.commit() 99 100 # 2.1 主模型已创建的情况[直接对物理外键的字段进行赋值] 101 stu_address = StudentAddress( 102 province="北京市", 103 city="北京市", 104 area="昌平区", 105 address="百沙路207号", 106 user_id=4, # 如果主模型已经创建,则直接设置物理外键的值即可 107 ) 108 db.session.add(stu_address) 109 db.session.commit() 110 111 #2.2 主模型已创建的情况[使用查询出来的模型对象,通过关联属性进行赋值] 112 stu_address = StudentAddress( 113 province="北京市", 114 city="北京市", 115 area="昌平区", 116 address="百沙路208号", 117 student= Student.query.get(4), # 如果需要通过关联属性设置,则需要先把模型对象查询出来 118 ) 119 db.session.add(stu_address) 120 db.session.commit() 121 122 """查询数据""" 123 # 正向关联----> 从主模型查询外键模型 124 student = Student.query.filter(Student.name=="xiaobai").first() 125 # 获取地址列表 126 print(student.address_list) 127 print(student.address_list[0].address) 128 129 # 反向关联----> 从外键模型查询主模型 130 sa = StudentAddress.query.get(4) 131 print(sa.student) 132 print(sa.student.name) 133 134 """修改数据""" 135 # 通过主表使用关联属性可以修改附加表的数据 136 student = Student.query.filter(Student.name == "xiaobai").first() 137 student.address_list[0].address = "南丰路103号" 138 db.session.commit() 139 140 # 也可以通过附加表模型直接修改主表的数据 141 sa = StudentAddress.query.filter(StudentAddress.address=="南丰路103号").first() 142 # StudentAddress查找Student查找StudentInfo 143 sa.student.info.address = sa.address 144 db.session.commit() 145 return "ok" 146 147 if __name__ == '__main__': 148 with app.app_context(): 149 # 检测数据库中是否存在和模型匹配的数据表。 150 # 如果没有,则根据模型转换的建表语句进行建表。 151 # 如果找到,则不会进行额外处理 152 153 db.create_all() 154 app.run(debug=True)
from flask import Flask,render_template,request from flask_sqlalchemy import SQLAlchemy app = Flask(__name__) class Config(object): DEBUG = True # 数据库连接配置 # SQLALCHEMY_DATABASE_URI = "数据库类型://数据库账号:密码@数据库地址:端口/数据库名称?charset=utf8mb4" SQLALCHEMY_DATABASE_URI = "mysql://root:123@127.0.0.1:3306/students?charset=utf8mb4" # 动态追踪修改设置,如未设置只会提示警告 SQLALCHEMY_TRACK_MODIFICATIONS = True # 查询时会显示原始SQL语句 SQLALCHEMY_ECHO = True app.config.from_object(Config) """模型类定义""" db = SQLAlchemy(app=app) # 多对多关系表 achievement = db.Table( 'db_achievement', db.Column('id', db.Integer, primary_key=True), db.Column('student_id', db.Integer, db.ForeignKey('db_students.id')), db.Column('course_id', db.Integer, db.ForeignKey('db_course.id')), ) class Student(db.Model): """学生信息模型""" __tablename__ = "db_students" id = db.Column(db.Integer, primary_key=True,comment="主键") name = db.Column(db.String(15), comment="姓名") age = db.Column(db.SmallInteger, comment="年龄") sex = db.Column(db.Boolean, default=True, comment="性别") email = db.Column(db.String(128), comment="邮箱地址") money = db.Column(db.Numeric(10,2), default=0.0, comment="钱包") course_list = db.relationship("Course",secondary=achievement, backref="student_list", lazy="dynamic") def __repr__(self): return f"{self.name}<Student>" class Course(db.Model): """课程数据模型""" __tablename__ = "db_course" id = db.Column(db.Integer, primary_key=True, comment="主键") name = db.Column(db.String(64), unique=True, comment="课程") price = db.Column(db.Numeric(7, 2)) def __repr__(self): return f'{self.name}<Course>'
1 from flask import Flask,render_template,request 2 from flask_sqlalchemy import SQLAlchemy 3 4 app = Flask(__name__) 5 6 class Config(object): 7 DEBUG = True 8 # 数据库连接配置 9 # SQLALCHEMY_DATABASE_URI = "数据库类型://数据库账号:密码@数据库地址:端口/数据库名称?charset=utf8mb4" 10 SQLALCHEMY_DATABASE_URI = "mysql://root:123@127.0.0.1:3306/students?charset=utf8mb4" 11 # 动态追踪修改设置,如未设置只会提示警告 12 SQLALCHEMY_TRACK_MODIFICATIONS = True 13 # 查询时会显示原始SQL语句 14 SQLALCHEMY_ECHO = True 15 16 app.config.from_object(Config) 17 18 19 """模型类定义""" 20 db = SQLAlchemy(app=app) 21 22 # 多对多关系表 23 achievement = db.Table( 24 'db_achievement', 25 db.Column('id', db.Integer, primary_key=True), 26 db.Column('student_id', db.Integer, db.ForeignKey('db_students.id')), 27 db.Column('course_id', db.Integer, db.ForeignKey('db_course.id')), 28 ) 29 30 class Student(db.Model): 31 """学生信息模型""" 32 __tablename__ = "db_students" 33 id = db.Column(db.Integer, primary_key=True,comment="主键") 34 name = db.Column(db.String(15), comment="姓名") 35 age = db.Column(db.SmallInteger, comment="年龄") 36 sex = db.Column(db.Boolean, default=True, comment="性别") 37 email = db.Column(db.String(128), comment="邮箱地址") 38 money = db.Column(db.Numeric(10,2), default=0.0, comment="钱包") 39 course_list = db.relationship("Course",secondary=achievement, backref="student_list", lazy="dynamic") 40 41 def __repr__(self): 42 return f"{self.name}<Student>" 43 44 class Course(db.Model): 45 """课程数据模型""" 46 __tablename__ = "db_course" 47 id = db.Column(db.Integer, primary_key=True, comment="主键") 48 name = db.Column(db.String(64), unique=True, comment="课程") 49 price = db.Column(db.Numeric(7, 2)) 50 51 def __repr__(self): 52 return f'{self.name}<Course>' 53 54 @app.route("/") 55 def index(): 56 """添加数据""" 57 58 # student = Student( 59 # name="xiaozhao", 60 # age=13, 61 # sex=False, 62 # money=30000, 63 # email="100000@qq.com", 64 # course_list=[ 65 # Course(name="python入门", price=99.99), 66 # Course(name="python初级", price=199.99), 67 # Course(name="python进阶", price=299.99), 68 # ] 69 # ) 70 # db.session.add(student) 71 # db.session.commit() 72 73 # student = Student.query.get(4) 74 # # student.course_list = [Course.query.get(2)] #错误写法!!! 如果数据中已经存在了课程列表了,则不要重新赋值,会变成删除操作的 75 # student.course_list.append(Course.query.get(3)) 76 # db.session.commit() 77 78 """查询操作""" 79 # student = Student.query.get(4) 80 # course_list = [{"name":item.name,"price":float(item.price)} for item in student.course_list] 81 82 # 查询出2号课程,都有谁在读? 83 # course = Course.query.get(2) 84 # student_list = [{"name":item.name,"money":float(item.money)} for item in course.student_list] 85 # print(student_list) 86 87 88 """更新数据""" 89 # 给报读了3号课程的同学,返现红包200块钱 90 course = Course.query.get(3) 91 for student in course.student_list: 92 student.money+=200 93 94 db.session.commit() 95 96 return "ok" 97 98 if __name__ == '__main__': 99 with app.app_context(): 100 db.create_all() 101 app.run(debug=True)
from flask import Flask,render_template,request from flask_sqlalchemy import SQLAlchemy app = Flask(__name__) class Config(object): DEBUG = True # 数据库连接配置 # SQLALCHEMY_DATABASE_URI = "数据库类型://数据库账号:密码@数据库地址:端口/数据库名称?charset=utf8mb4" SQLALCHEMY_DATABASE_URI = "mysql://root:123@127.0.0.1:3306/students?charset=utf8mb4" # 动态追踪修改设置,如未设置只会提示警告 SQLALCHEMY_TRACK_MODIFICATIONS = True # 查询时会显示原始SQL语句 SQLALCHEMY_ECHO = True app.config.from_object(Config) """模型类定义""" db = SQLAlchemy(app=app) class Student(db.Model): """学生信息模型""" __tablename__ = "db_students" id = db.Column(db.Integer, primary_key=True,comment="主键") name = db.Column(db.String(15), comment="姓名") age = db.Column(db.SmallInteger, comment="年龄") sex = db.Column(db.Boolean, default=True, comment="性别") email = db.Column(db.String(128), comment="邮箱地址") money = db.Column(db.Numeric(10,2), default=0.0, comment="钱包") achievement_list = db.relationship("Achievement", uselist=True, backref="student") def __repr__(self): return f"{self.name}<Student>" class Course(db.Model): """课程数据模型""" __tablename__ = "db_course" id = db.Column(db.Integer, primary_key=True, comment="主键") name = db.Column(db.String(64), unique=True, comment="课程") price = db.Column(db.Numeric(7, 2)) achievement_list = db.relationship("Achievement", uselist=True, backref="course") def __repr__(self): return f'{self.name}<Course>' from datetime import datetime class Achievement(db.Model): __tablename__ = "db_achievement" id = db.Column(db.Integer, primary_key=True, comment="主键") student_id = db.Column(db.Integer, db.ForeignKey(Student.id)) course_id = db.Column(db.Integer, db.ForeignKey(Course.id)) score = db.Column(db.Numeric(4,1), default=0, comment="成绩") time = db.Column(db.DateTime, default=datetime.now, comment="考试时间")
1 from flask import Flask,render_template,request 2 from flask_sqlalchemy import SQLAlchemy 3 4 app = Flask(__name__) 5 6 class Config(object): 7 DEBUG = True 8 # 数据库连接配置 9 # SQLALCHEMY_DATABASE_URI = "数据库类型://数据库账号:密码@数据库地址:端口/数据库名称?charset=utf8mb4" 10 SQLALCHEMY_DATABASE_URI = "mysql://root:123@127.0.0.1:3306/students?charset=utf8mb4" 11 # 动态追踪修改设置,如未设置只会提示警告 12 SQLALCHEMY_TRACK_MODIFICATIONS = True 13 # 查询时会显示原始SQL语句 14 SQLALCHEMY_ECHO = True 15 16 app.config.from_object(Config) 17 18 19 """模型类定义""" 20 db = SQLAlchemy(app=app) 21 22 class Student(db.Model): 23 """学生信息模型""" 24 __tablename__ = "db_students" 25 id = db.Column(db.Integer, primary_key=True,comment="主键") 26 name = db.Column(db.String(15), comment="姓名") 27 age = db.Column(db.SmallInteger, comment="年龄") 28 sex = db.Column(db.Boolean, default=True, comment="性别") 29 email = db.Column(db.String(128), comment="邮箱地址") 30 money = db.Column(db.Numeric(10,2), default=0.0, comment="钱包") 31 achievement_list = db.relationship("Achievement", uselist=True, backref="student") 32 def __repr__(self): 33 return f"{self.name}<Student>" 34 35 class Course(db.Model): 36 """课程数据模型""" 37 __tablename__ = "db_course" 38 id = db.Column(db.Integer, primary_key=True, comment="主键") 39 name = db.Column(db.String(64), unique=True, comment="课程") 40 price = db.Column(db.Numeric(7, 2)) 41 achievement_list = db.relationship("Achievement", uselist=True, backref="course") 42 def __repr__(self): 43 return f'{self.name}<Course>' 44 45 from datetime import datetime 46 class Achievement(db.Model): 47 __tablename__ = "db_achievement" 48 id = db.Column(db.Integer, primary_key=True, comment="主键") 49 student_id = db.Column(db.Integer, db.ForeignKey(Student.id)) 50 course_id = db.Column(db.Integer, db.ForeignKey(Course.id)) 51 score = db.Column(db.Numeric(4,1), default=0, comment="成绩") 52 time = db.Column(db.DateTime, default=datetime.now, comment="考试时间") 53 54 @app.route("/") 55 def index(): 56 """添加数据""" 57 # 记录xiaobai本次的python入门考试成绩: 88 58 # achievement = Achievement( 59 # student= Student.query.filter(Student.name=="xiaobai").first(), 60 # course = Course.query.filter(Course.name=="python初级").first(), 61 # score = 81 62 # ) 63 # db.session.add(achievement) 64 # db.session.commit() 65 66 """查询操作""" 67 # 查询xiaobai的成绩 68 student = Student.query.filter(Student.name=="xiaobai").first() 69 for achievement in student.achievement_list: 70 print(f"课程:{achievement.course.name},成绩:{achievement.score}") 71 72 return "ok" 73 74 if __name__ == '__main__': 75 with app.app_context(): 76 db.create_all() 77 app.run(debug=True)
from flask import Flask,render_template,request from flask_sqlalchemy import SQLAlchemy app = Flask(__name__) class Config(object): DEBUG = True # 数据库连接配置 # SQLALCHEMY_DATABASE_URI = "数据库类型://数据库账号:密码@数据库地址:端口/数据库名称?charset=utf8mb4" SQLALCHEMY_DATABASE_URI = "mysql://root:123@127.0.0.1:3306/students?charset=utf8mb4" # 动态追踪修改设置,如未设置只会提示警告 SQLALCHEMY_TRACK_MODIFICATIONS = True # 查询时会显示原始SQL语句 SQLALCHEMY_ECHO = True app.config.from_object(Config) """模型类定义""" db = SQLAlchemy(app=app) class Student(db.Model): """学生信息模型""" __tablename__ = "db_students" id = db.Column(db.Integer, primary_key=True,comment="主键") name = db.Column(db.String(15), comment="姓名") age = db.Column(db.SmallInteger, comment="年龄") sex = db.Column(db.Boolean, default=True, comment="性别") email = db.Column(db.String(128), comment="邮箱地址") money = db.Column(db.Numeric(10,2), default=0.0, comment="钱包") def __repr__(self): return f"{self.name}<Student>" class Course(db.Model): """课程数据模型""" __tablename__ = "db_course" id = db.Column(db.Integer, primary_key=True, comment="主键") name = db.Column(db.String(64), unique=True, comment="课程") price = db.Column(db.Numeric(7, 2)) def __repr__(self): return f'{self.name}<Course>' from datetime import datetime class Achievement(db.Model): __tablename__ = "db_achievement" id = db.Column(db.Integer, primary_key=True, comment="主键") student_id = db.Column(db.Integer, comment="学生ID") course_id = db.Column(db.Integer, comment="课程ID") score = db.Column(db.Numeric(4,1), default=0, comment="成绩") time = db.Column(db.DateTime, default=datetime.now, comment="考试时间")
6.2 逻辑外键的数据操作
模型.query.join("模型类","主模型.主键==外键模型.外键").with_entities("字段1","字段2".label("字段别名")).all()
1 from flask import Flask,render_template,request 2 from flask_sqlalchemy import SQLAlchemy 3 4 app = Flask(__name__) 5 6 class Config(object): 7 DEBUG = True 8 # 数据库连接配置 9 # SQLALCHEMY_DATABASE_URI = "数据库类型://数据库账号:密码@数据库地址:端口/数据库名称?charset=utf8mb4" 10 SQLALCHEMY_DATABASE_URI = "mysql://root:123@127.0.0.1:3306/students?charset=utf8mb4" 11 # 动态追踪修改设置,如未设置只会提示警告 12 SQLALCHEMY_TRACK_MODIFICATIONS = True 13 # 查询时会显示原始SQL语句 14 SQLALCHEMY_ECHO = True 15 16 app.config.from_object(Config) 17 18 19 """模型类定义""" 20 db = SQLAlchemy(app=app) 21 22 class Student(db.Model): 23 """学生信息模型""" 24 __tablename__ = "db_students" 25 id = db.Column(db.Integer, primary_key=True,comment="主键") 26 name = db.Column(db.String(15), comment="姓名") 27 age = db.Column(db.SmallInteger, comment="年龄") 28 sex = db.Column(db.Boolean, default=True, comment="性别") 29 email = db.Column(db.String(128), comment="邮箱地址") 30 money = db.Column(db.Numeric(10,2), default=0.0, comment="钱包") 31 def __repr__(self): 32 return f"{self.name}<Student>" 33 34 class Course(db.Model): 35 """课程数据模型""" 36 __tablename__ = "db_course" 37 id = db.Column(db.Integer, primary_key=True, comment="主键") 38 name = db.Column(db.String(64), unique=True, comment="课程") 39 price = db.Column(db.Numeric(7, 2)) 40 def __repr__(self): 41 return f'{self.name}<Course>' 42 43 from datetime import datetime 44 class Achievement(db.Model): 45 __tablename__ = "db_achievement" 46 id = db.Column(db.Integer, primary_key=True, comment="主键") 47 student_id = db.Column(db.Integer, comment="学生ID") 48 course_id = db.Column(db.Integer, comment="课程ID") 49 score = db.Column(db.Numeric(4,1), default=0, comment="成绩") 50 time = db.Column(db.DateTime, default=datetime.now, comment="考试时间") 51 52 @app.route("/") 53 def index(): 54 """添加数据""" 55 # 记录xiaobai本次的python入门考试成绩: 88 56 # achievement = Achievement( 57 # student_id = Student.query.filter(Student.name=="xiaobai").first().id, 58 # course_id = Course.query.filter(Course.name=="python入门").first().id, 59 # score = 80, 60 # time = datetime.now(), 61 # ) 62 # db.session.add(achievement) 63 # db.session.commit() 64 65 """查询操作""" 66 # 查询xiaobai的成绩 67 student = Student.query.join( 68 Achievement, 69 Achievement.student_id == Student.id 70 ).join( 71 Course, 72 Course.id == Achievement.course_id 73 ).filter( 74 Student. 75 =="xiaobai", 76 Achievement.score==88, 77 ).with_entities( 78 Student.name, 79 Course.name.label("course"), 80 Achievement.score.label("number") 81 ).first() 82 83 # 当连表查询返回一个结果的时候,可以通过keys查看当前模型提供的字段 84 print(student) # 字段列表名 85 print(type(student)) # 返回值是一个SQLAlchemy内部封装的模型对象 86 print(student.keys()) # 字段列表 87 print(f"{student.name}的{student.course}成绩是:{student.number}") 88 89 return "ok" 90 91 if __name__ == '__main__': 92 with app.app_context(): 93 db.create_all() 94 app.run(debug=True)
注意:django中也有虚拟外键的设置方案:在模型中设置db_constraint = False
七、lazy 懒加载的用法
7.1 懒加载简介
class Teacher(db.Model): ... # 关联属性,一的一方添加模型关联属性 course = db.relationship("Course", uselist=True, backref="teacher",lazy='dynamic') class Course(db.Model): ... # 外键,多的一方模型中添加外间 teacher_id = db.Column(db.Integer, db.ForeignKey(Teacher.id))
-
-
第二个参数backref为类Teacher申明新属性的方法
-
第三个参数lazy决定了什么时候SQLALchemy从数据库中加载数据
-
lazy='subquery',查询当前数据模型时,采用子查询(subquery),把外键模型的属性也瞬间查询出来了。
-
lazy=True或lazy='select',查询当前数据模型时,不会把外键模型的数据查询出来,只有操作到外键关联属性时,才进行连表查询数据[执行SQL]
-
lazy='dynamic',查询当前数据模型时,不会把外键模型的数据查询出来,只有操作到外键关联属性并操作外键模型具体属性时,才进行连表查询数据[执行SQL]
-
-
常用的lazy选项:dynamic和select
7.2 操作实例
1 from flask import Flask,render_template,request 2 from flask_sqlalchemy import SQLAlchemy 3 4 app = Flask(__name__) 5 6 class Config(object): 7 DEBUG = True 8 # 数据库连接配置 9 # SQLALCHEMY_DATABASE_URI = "数据库类型://数据库账号:密码@数据库地址:端口/数据库名称?charset=utf8mb4" 10 SQLALCHEMY_DATABASE_URI = "mysql://root:123@127.0.0.1:3306/students?charset=utf8mb4" 11 # 动态追踪修改设置,如未设置只会提示警告 12 SQLALCHEMY_TRACK_MODIFICATIONS = True 13 # 查询时会显示原始SQL语句 14 SQLALCHEMY_ECHO = True 15 16 app.config.from_object(Config) 17 18 19 """模型类定义""" 20 db = SQLAlchemy(app=app) 21 # 等同于 22 # db = SQLAlchemy() 23 # db.init_app(app) 24 25 class Student(db.Model): 26 """学生信息模型""" 27 # 声明与当前模型绑定的数据表名称 28 __tablename__ = "db_students" 29 id = db.Column(db.Integer, primary_key=True,comment="主键") 30 name = db.Column(db.String(15), comment="姓名") 31 age = db.Column(db.SmallInteger, comment="年龄") 32 sex = db.Column(db.Boolean, default=True, comment="性别") 33 email = db.Column(db.String(128), comment="邮箱地址") 34 money = db.Column(db.Numeric(10,2), default=0.0, comment="钱包") 35 # 从Student 查询 StudentAddress: Student.address_list = [] 36 # 从StudentAddress 查询 Student: StudentAddress.student = 学生模型对象 37 address_list = db.relationship("StudentAddress", uselist=True, backref="student",lazy="dynamic") 38 39 def __repr__(self): 40 return f"{self.name}<Student>" 41 42 from sqlalchemy.orm import backref 43 44 class StudentAddress(db.Model): 45 """学生收货地址""" 46 __tablename__ = "db_student_address" 47 id = db.Column(db.Integer, primary_key=True, comment="主键") 48 user_id = db.Column(db.ForeignKey("db_students.id"), comment="学生id") 49 province = db.Column(db.String(20), comment="省份") 50 city = db.Column(db.String(20), comment="城市") 51 area = db.Column(db.String(20), comment="地区") 52 address = db.Column(db.String(250), comment="详细接地") 53 # 也可以在外键模型中声明关系熟悉 54 # student = db.relationship("Student", uselist=False, backref=backref("address_list",uselist=True)) 55 56 def __repr__(self): 57 return f"{self.province}-{self.city}-{self.area}-{self.address}" 58 59 @app.route("/") 60 def index(): 61 """查询数据""" 62 # 正向关联----> 从主模型查询外键模型 63 student = Student.query.filter(Student.name=="xiaobai").first() 64 print(student) 65 # # 获取地址列表[调用关联属性,直接把外建模型对应数据直接查询查来] 66 address_list = student.address_list[0].address 67 return "ok" 68 69 """ 70 lazy="subquery" 71 1. 只查询:student,但是同时使用子查询语句进行链表操作,把外键模型数据也查询出来了 72 73 SELECT db_students.id AS db_students_id, db_students.name AS db_students_name, db_students.age AS db_students_age, db_students.sex AS db_students_sex, db_students.email AS db_students_email, db_students.money AS db_students_money 74 FROM db_students 75 76 SELECT db_student_address.id AS db_student_address_id, db_student_address.user_id AS db_student_address_user_id, db_student_address.province AS db_student_address_province, db_student_address.city AS db_student_address_city, db_student_address.area AS db_student_address_area, db_student_address.address AS db_student_address_address, anon_1.db_students_id AS anon_1_db_students_id 77 FROM (SELECT db_students.id AS db_students_id FROM db_students WHERE db_students.name = %s LIMIT %s) AS anon_1 78 INNER JOIN db_student_address ON anon_1.db_students_id = db_student_address.user_id 79 80 lazy="select", 81 1. 只查询:student 82 SELECT db_students.id AS db_students_id, db_students.name AS db_students_name, db_students.age AS db_students_age, db_students.sex AS db_students_sex, db_students.email AS db_students_email, db_students.money AS db_students_money 83 FROM db_students WHERE db_students.name = %s LIMIT %s 84 85 2. 调用关联属性,直接连表查询 86 SELECT db_students.id AS db_students_id, db_students.name AS db_students_name, db_students.age AS db_students_age, db_students.sex AS db_students_sex, db_students.email AS db_students_email, db_students.money AS db_students_money 87 FROM db_students WHERE db_students.name = %s LIMIT %s 88 89 SELECT db_student_address.id AS db_student_address_id, db_student_address.user_id AS db_student_address_user_id, db_student_address.province AS db_student_address_province, db_student_address.city AS db_student_address_city, db_student_address.area AS db_student_address_area, db_student_address.address AS db_student_address_address 90 FROM db_student_address WHERE %s = db_student_address.user_id 91 92 lazy="dynamic" 93 1. 只查询:student 94 SELECT db_students.id AS db_students_id, db_students.name AS db_students_name, db_students.age AS db_students_age, db_students.sex AS db_students_sex, db_students.email AS db_students_email, db_students.money AS db_students_money 95 FROM db_students WHERE db_students.name = %s LIMIT %s 96 97 2. 调用关联属性,不连表,直到代码真的调用了外键模型的具体字段才会查询数据库 98 SELECT db_students.id AS db_students_id, db_students.name AS db_students_name, db_students.age AS db_students_age, db_students.sex AS db_students_sex, db_students.email AS db_students_email, db_students.money AS db_students_money 99 FROM db_students WHERE db_students.name = %s LIMIT %s 100 101 """ 102 103 if __name__ == '__main__': 104 with app.app_context(): 105 # 检测数据库中是否存在和模型匹配的数据表。 106 # 如果没有,则根据模型转换的建表语句进行建表。 107 # 如果找到,则不会进行额外处理 108 109 db.create_all() 110 app.run(debug=True)