Flask 学习笔记
一、一对多
表之间的关系存在三种:一对一、一对多、多对多。而 SQLAlchemy 中的 ORM 也可以模拟这三种关系。因为一对一其实在 SQLAlchemy 中底层是通过一对多的方式模拟的。
1.1、一对多
如上 user2 表中的一条数据与 article2 表的多条数据存在关联。为了方便查询我们可以使用 relationship
在创建类时使两表建立关联。
class Article2(Base):
__tablename__ = 'article2'
id = Column(Integer, primary_key=True, autoincrement=True)
title = Column(String(50))
content = Column(Text, nullable=False)
uid = Column(Integer, ForeignKey('user2.id', ondelete='SET NULL'))
# 建立关联
author = relationship("User2")
def __str__(self):
return f"{self.title} {self.content} {self.uid}"
class User2(Base):
__tablename__ = 'user2'
id = Column(Integer, primary_key=True, autoincrement=True)
username = Column(String(50), nullable=False)
# 建立关联
articles = relationship("Article2")
def __str__(self):
return f"{self.id} {self.username}"
# Base.metadata.drop_all()
Base.metadata.create_all()
session = sessionmaker(bind=engine)()
也可以在一个类中创建一条:
# 反向访问的属性(这是在 User2 类中设置的)
# author 变量名可以随便取, 访问时写对就行
articles = relationship("Article2", backref='author')
数据
1.2、几个查询示例:
# 查询 article2 表中第一条记录所对应的 user 表中的用户名
res = session.query(Article2).first()
# 这里的 author 是在 User2 类中定义的, 返回的是 外键所对应的记录
print(res)
print(res.author)
# 查询 bb 所对应的用户名
res = session.query(Article2).filter(Article2.title == 'bb')
# print(res)
for i in res:
print(i)
# 查询 1 所对应的 article2 表中的记录
res = session.query(User2).filter(User2.username == 'a')
for i in res:
print(i)
for data in i.articles:
print(data)
1.3、数据添加:
# 添加单条数据
user = User2(username='张三')
article = Article2(title='PHP', content='xxxx')
article.author = user # 该句用来为父表添加数据
session.add(article) # 虽然看起来只有 article2 表进行了添加操作, 实际上两个表都添加了数据
session.commit()
# 添加多条数据
user = session.query(User2).first()
article1 = Article2(title='JS', content='xxxx1')
article2 = Article2(title='Java', content='xxxx2')
article1.author = user
article2.author = user
session.add(article1)
session.add(article2)
session.commit()
二、一对一
一对一其实就是一对多的特殊情况。从以上的一对多例子中不难发现,一对多是指 user2
表中的一条记录对应 article2
表中的多条数据。因此,要将一对多转换成一对一,只要设置一个 User2
对象对应一个 Article2
对象即可。通过设置 uselist=False
实现。
articles = relationship("Article2", backref='author', uselist=False)
应用举例:
现某网站要存储 1000 个用户的信息,收集到的用户信息大致分为 20 项,其中 6 项为常用项(如 用户名、密码等),14 项为非常用项(如 性别、年龄等)。因此,为了方便查询管理分别用两个表存储这些数据,那么这两个表中的数据就是一对一的关系。
三、对多对
3.1、创建
多对多需要一个中间表来作为连接,同理在 sqlalchemy 中的 orm 也需要一个中间表。假如现在有一个 Teacher
和一个 Classes
表,即老师和班级,一个老师可以教多个班级,一个班级有多个老师,是一种典型的多对多的关系,那么通过 sqlalchemy 的 ORM 的实现方式。要创建一个多对多的关系表,首先需要一个中间表,通过Table来创建一个中间表。
Table 的几个参数:
-
第一个参数:代表的是中间表的表名;
-
第二个参数:是Base的元类;
-
第三个和第四个参数:是要连接的两个表(用到 Column 其中也有三个参数)。
(1) 第1个参数:表示的是连接表的外键名
(2) 第2个参数:表示这个外键的类型
(3) 第3个参数:表示要外键的表名和字段
from sqlalchemy import Table
# 创建一个中间表, 用于存储两个表的外键(需要导入 Table)
association_table = Table(
'teacher_classes',
Base.metadata,
Column('teacher_id',Integer,ForeignKey('teacher.id')),
Column('classes_id',Integer,ForeignKey('classes.id'))
)
class Teacher(Base):
__tablename__ = 'teacher'
id = Column(Integer, primary_key=True)
tno = Column(String(10))
name = Column(String(50))
age = Column(Integer)
# 通过 secondary 属性与中间表建立联系
classes = relationship('Classes', secondary=association_table, backref='teachers')
class Classes(Base):
__tablename__ = 'classes'
id = Column(Integer, primary_key=True)
cno = Column(String(10))
name = Column(String(50))
3.2、添加数据(顺便介绍一种给外键添加数据的方法 append()
)
teacher1 = Teacher(name='MathTC')
teacher2 = Teacher(name='EnglishTC')
class1 = Classes(name='c1')
class2 = Classes(name='c2')
teacher1.classes.append(class1)
teacher1.classes.append(class2)
session.add(teacher1)
class2.teachers.append(teacher1)
class2.teachers.append(teacher2)
session.add(class2)
session.commit()
3.3、查询测试
# 老师对应的班级
teacher = session.query(Teacher).first()
print("\n老师对应的班级\n", teacher)
for i in teacher.classes:
print(i)
# 班级对应的老师
classes = session.query(Classes).first()
print("\n班级对应的老师\n", classes)
for i in classes.teachers:
print(i)