本章节介绍
SQLAlchemy
的表关系,主要分为以下几种
- 1、一对多关系
- 2、一对一的关系
- 3、多对多的关系
一、一对多的关系
在多表关联中,常见的是一对多的关系,但是有时候我们也会听到多对一的关系,其实他们仅仅是站在不同的角度上来看的表关系,(本案例中采用用户与文章来说明)
- 1、一个用户可以写多篇文章(用户对文章是一对多的关系)
- 2、文章只能有一个用户(多对一的关系)
具体的代码实现
- 1、基本的导包
from sqlalchemy import Column, Integer, String, DateTime, Boolean, TIMESTAMP, func
from sqlalchemy.orm import relationship
from sqlalchemy_demo.connect import Base
from sqlalchemy import ForeignKey
- 2、创建一个用户表的
module
class UserModule(Base):
"""
创建一个用户的数据模型
"""
__tablename__ = 'user'
id = Column(Integer, primary_key=True, autoincrement=True, comment='用户id')
user_name = Column(String(30), nullable=False, unique=True, comment='用户名')
password = Column(String(64), nullable=False, comment='用户密码')
def __repr__(self):
return 'User({},{})'.format(self.user_name, self.password)
- 3、创建一个文章表的
module
class ArticleList(Base):
"""
文章列表页面
"""
__tablename__ = 'article_list'
id = Column(Integer, primary_key=True, autoincrement=True, comment='文章id')
title = Column(String(100), nullable=False, default='', comment='文章标题')
def __repr__(self):
return 'ArticleList({})'.format(self.title)
- 4、在子表中(相对来说是多的那端)使用
ForeignKey
关联到父表(注意数据类型要一致)
class ArticleList(Base):
"""
文章列表页面
"""
...
# 外键关联(关联的key的类型要和定义的类型一致)
user_id = Column(Integer, ForeignKey(UserModule.id), comment='文章作者')
...
- 5、在父表中使用
relationship
方法来引用子表的数据(就是说关联了,可以通过父表查询到子表的数据[本案例中:根据用户查询到文字])
class UserModule(Base):
"""
创建一个用户的数据模型
"""
...
article_list = relationship('ArticleList')
...
- 6、上面仅仅是建立的父表可以访问到子表的数据,如果要子表也要访问到父表的数据就在
relationship
中多加一个参数backref
class UserModule(Base):
"""
创建一个用户的数据模型
"""
...
article_list = relationship('ArticleList', backref='user')
...
- 7、子表访问父表还有另外一种方式,使用
back_populates
(和上面方法任选一个)- 在父表中
class UserModule(Base):
"""
创建一个用户的数据模型
"""
...
article_list = relationship('ArticleList', back_populates='user')
* 在子表中
class ArticleList(Base):
"""
文章列表页面
"""
__tablename__ = 'article_list'
...
# 外键关联
user_id = Column(Integer, ForeignKey(UserModule.id), comment='文章作者')
# 通过关联起来,这样在文章列表页面可以获取用户表的信息
user = relationship(UserModule, back_populates='article_list')
- 8、测试一(父表查询到子表数据)
...
def query_user():
rows = dbSession.query(UserModule).first() # 获取到父表第一条数据
print(rows.article_list) # 获取
...
- 9、测试二(子表查询到父表数据)
...
def query_user():
rows = dbSession.query(ArticleList).first() # 获取到文章的第一条数据
print(rows.user) # 获取文章的作者
...
二、一对一的关系
常见的一对一的关系,一般是表的扩展,比如用户表及用户扩展表,文章及文章详情这样的,操作方式也很简单,只要在一对多的基础上加上uselist=False
就可以
- 1、用户模型
class UserModule(Base):
"""
创建一个用户的数据模型
"""
__tablename__ = 'user'
id = Column(Integer, primary_key=True, autoincrement=True, comment='用户id')
user_name = Column(String(30), nullable=False, unique=True, comment='用户名')
password = Column(String(64), nullable=False, comment='用户密码')
# 一对多关系中关联文章列表的
article_list = relationship('ArticleList', backref='user')
def __repr__(self):
return 'User({},{})'.format(self.user_name, self.password)
- 2、用户扩展表
class UserExtendModule(Base):
"""
用户扩展的模型
"""
__tablename__ = 'user_extend'
id = Column(Integer, primary_key=True, autoincrement=True, comment='id')
gender = Column(String(3), nullable=True, comment='性别')
birthday = Column(DateTime, nullable=True, comment='出生年月')
position = Column(String(20), nullable=True, comment='职位')
# 外键关联到用户表
user_id = Column(Integer, ForeignKey(UserModule.id), unique=True, comment='关联父id')
# 创建关系,用户扩展表与用户表建立关系
user = relationship('UserModule', backref='user_detail', uselist=False, cascade='all')
def __repr__(self):
return 'user extend({},{}, {})'.format(self.gender, self.birthday, self.position)
- 3、测试代码
- 1.用户表查找到用户扩展表
def query_user():
rows = dbSession.query(UserModule).first()
print(dir(rows))
print(rows.user_detail)
* 2.反向查找(用户扩展表查找到用户)
def query_user():
rows = dbSession.query(UserExtendModule).first()
print(dir(rows))
print(rows.user)
三、关于relationship(module, backref='', uselist=True, cascade='')
的参数介绍
- 1、
module
关联的数据模型(如果是在当前的上面可以不加引号) - 2、
backref
在关联的module
中添加属性 - 3、
uselist
默认是True
表示一对多的关系,如果是一对一的关系就要设置False
- 4、
cascade
自动关系处理(比如一对一中删除父表数据,子表数据是否删除)
四、关于cascade
几个属性的介绍
- 1、
all
:所有操作都会自动处理到关联对象上 - 2、
save-update
:关联对象自动添加到会话上 - 3、
delete
:关联对象自动从会话中删除 - 4、
delete-orphan
:属性中去掉关联对象,则会话中会自动删除关联对象 - 5、
merge
:session.merge()
时会处理关联对象 - 6、
refresh-expire
:session.expire()
时会处理关联对象 - 7、
expunge
:session.expunge()
时会处理关联对象
五、多对多的关系
在
mysql
中处理多对多的关系的时候,我们都是创建一个第三张表,使用上面的一对多的技术,本案例使用(文章与tag
来描素多对多的关系)
- 1、文章表
class ArticleList(Base):
"""
文章列表页面
"""
__tablename__ = 'article_list'
id = Column(Integer, primary_key=True, autoincrement=True, comment='文章id')
title = Column(String(100), nullable=False, default='', comment='文章标题')
# 外键关联
user_id = Column(Integer, ForeignKey(UserModule.id), comment='文章作者')
def __repr__(self):
return 'ArticleList({})'.format(self.title)
- 2、创建一个
tag
表
class TagModule(Base):
"""
文章Tag模型
"""
__tablename__ = 'tag'
id = Column(Integer, primary_key=True, autoincrement=True, comment='主键')
name = Column(String(30), nullable=False, default='', comment='tag名字')
def __repr__(self):
return 'TagModule({},{})'.format(self.id, self.name)
- 3、导包
Table
from sqlalchemy import ForeignKey, Table
- 4、创建中间表
article_tag = Table(
'article_tag',
Base.metadata,
Column('article_id', Integer, ForeignKey(ArticleList.id), primary_key=True, comment='文章id'),
Column('tag_id', Integer, ForeignKey(TagModule.id), primary_key=True, comment='tag表id')
)
- 5、在
TagModule
数据模型中新增关联关系
class TagModule(Base):
"""
文章Tag模型
"""
# secondary指向中间表,是表名
...
tag_article = relationship(ArticleList, backref='tags', secondary='article_tag')
...
- 6、手动插入数据
- 7、测试
- 1.根据文章查找到
tag
- 1.根据文章查找到
def query_user():
rows = dbSession.query(ArticleList).first()
print(dir(rows))
print(rows.tags)
* 2.从`tag`表中查找文章
def query_user():
rows = dbSession.query(TagModule).first()
print(dir(rows))
print(rows.tag_article)