FastAPI之各种模型类之间的关联关系
一、一对多和多对一关联
比如:作者和⽂章之间,部门和员工之间都是一对多的关联关系。反过来就是:多对一的关联关系。
1、定义外键约束
定义关系的第⼀步是创建外键。外键是(foreign key)⽤来在A表存储B表的主键值以便和B表建⽴联系的关系字段。
因为外键只能存储单⼀数据(标量),所以外键总是在“多”这⼀侧定义,多篇⽂章属于同⼀个作者,所以我们需要为每篇⽂章添加外键存储作者的主键值以指向对应的作者。在Article模型中,我们定义⼀个author_id字段作为外键:
注意ForeginKey的参数是<表名>.<键名>,⽽不是<类名>.<字段名>
多对⼀关联的外键
dept_id:Mapped[int]=mapped_column(ForeignKey(‘t_dept.id’))
2、定义关联属性和双向关联
我们在Author 类中定义了集合关系属性articles ,⽤来获取某个作者拥有的多篇⽂章记录。
在某些情况下,你也许希望能在Article 类中定义⼀个类似的author 关系属性,当被调⽤时返回对应的作者记录,⽽这种两侧都添加关系属性获取对⽅记录的关系我们称之为双向关系。双向关系并不是必须的,但在某些情况下会⾮常⽅便。
多对⼀关联的属性, back_populates写对⽅模型类中的关联属性名字
dept:Mapped[Optional[‘Dept’]]=relationship(back_populates=“emp_list”)
⼀对多的关联属性
emp_list:Mapped[List[‘Employee’]]=relationship(back_populates=‘dept’)
3、级联操作
cascade,默认选项为save-update:
1:save-update:默认选项,在添加⼀条数据的时候,会把其他和次数据关联的数据都添加到数据库中,这种⾏为就是save-update属性决定的。
• 2:delete:表⽰当删除某⼀个模型中的数据的时候,也删除掉使⽤relationship和此数据关联的数据。
• 3:delete-orphan:表⽰当对⼀个ORM对象解除了⽗表中的关联对象的时候,⾃⼰便会被删除,
如果⽗表的数据被删除,同样⾃⼰也会被删除,这个选项只能⽤在⼀对多上,不能⽤在多对多和多对⼀上,并且使⽤的时候还需要在⼦模型的relationship中增加参数:single_parent=True。
• 4:merge(合并):默认选项,当在使⽤session.merge合并⼀个对象的时候,会将使⽤了relationship相关联的对象也进⾏merge操作
• 5:expunge:移除操作的时候,会将相关联的对象也进⾏移除,这个操作只是从session中移除,并不会正则从数据库删除
• 6:all:对save-update、merge、refresh-expire、expunge、delete这⼏种的缩写
import enum
from datetime import date
from decimal import Decimal
from typing import Optional
from sqlalchemy import String, DECIMAL, Boolean, func, insert, select, text, update, delete, and_, or_, ForeignKey
from sqlalchemy.orm import Mapped, mapped_column, sessionmaker, relationship
from ch04.db_main import Base, engine
from ch05.models import Dept
class SexValue(enum.Enum):
"""通过枚举,可以给一些属性(字段)设置预设值"""
MALE = "男"
FEMALE = "女"
class Employee(Base):
"""员工的模型类"""
__tablename__ = "t_emp"
id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)
name: Mapped[str] = mapped_column(String(40), name="emp_name", unique=True, nullable=False) # 不允许为空
# DECIMAL:10:总位数,2:小数点后位数
sal: Mapped[Decimal] = mapped_column(DECIMAL(10, 2), nullable=True, comment="员工的基本薪资")
bonus: Mapped[int] = mapped_column(default=0, comment="员工的津贴")
is_leave: Mapped[bool] = mapped_column(Boolean, default=False, comment="员工是否离职,True表示离职,False表示在职")
gender: Mapped[SexValue]
entry_date: Mapped[date] = mapped_column(insert_default=func.now(), nullable=False, comment="入职时间")
# todo 和部门表关联的外键
dept_id:Mapped[Optional[int]]=mapped_column(ForeignKey('t_dept.id'),nullable=True)
# 定义关联属性:该员工所属的部门
dept:Mapped[Optional['Dept']]=relationship(back_populates="emp_list")
# 需要在Employee模型类中增加⼀个__str__函数