sqlmodel -- 处理一对多关系

文章目录

基于sqlmodel实现表之间的一对多关系,并创建模型类。

一对多关系

python 复制代码
"""
表关系: 一对多

heros_t:  英雄表
id  name  cate_id

cate_t:  类别表
id  name

一个类别可以对应多个英雄;
一个英雄只能属于一个类别;
"""
from typing import Annotated, Optional
# from sqlalchemy.orm import Relationship
from sqlmodel import Field, SQLModel, create_engine, Session, select, Relationship


# 创建英雄表的模型类
class Hero(SQLModel, table=True):
    # 指定映射后的表名
    __tablename__ = "hero_t"
    # id: Optional[int] = Field(default=None, primary_key=True)   python3.9 类型注释
    id: int | None = Field(default=None, primary_key=True)  # python3.10+ 后支持的类型注释
    name: str = Field(..., index=True, unique=True, nullable=False, description="英雄姓名")

    # 所属类别  int or None
    cate_id: Optional[int] = Field(default=None, foreign_key="cate_t.id")  # 外键,引用cate_t的id字段
    # 关系, 从模型类对象层面关联
    cate: Optional["Cate"] = Relationship(back_populates="heros")
    # back_populates表示 从另一方 反向查询英雄的属性

    # 打印对象时的输出
    def __repr_args__(self):
        # 必须返回列表
        return [
            ("name", self.name)
        ]


# 定义类别模型类
class Cate(SQLModel, table=True):
    __tablename__ = "cate_t"
    id: int | None = Field(default=None, primary_key=True)  # python3.10+ 支持的类型注释
    name: str = Field(..., unique=True, index=True, description="类别名称")

    # 模型类层面的关系关联
    heros: list["Hero"] = Relationship(back_populates="cate")

    # 打印对象时的输出
    def __repr_args__(self):
        return [
            ("id", self.id),
            ("name", self.name)
        ]


# 连接数据库,并创建所有的表
sqlite_file_name = "one_to_many.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

# echo= True 输出sqlalchemy日志
engine = create_engine(sqlite_url, echo=False, connect_args={"check_same_thread": True})


# 创建会话对象
def get_session():
    with Session(engine) as session:
        yield session


def create_db_and_tables():
    SQLModel.metadata.drop_all(engine)  # 删除所有的表及数据
    SQLModel.metadata.create_all(engine)


def main():
    # 创建所有的表
    create_db_and_tables()

    try:
        # 获取生成器
        generator = get_session()
        session = next(generator)
        # 创建英雄
        hero1 = Hero(name="寒冰射手")  # id为None
        hero2 = Hero(name="赏金猎人")
        hero3 = Hero(name="烬")
        # 创建类别
        cate1 = Cate(name="射手")

        # (关系) 关联
        hero1.cate = cate1
        hero2.cate = cate1
        hero3.cate = cate1

        # insert into  tables
        session.add(hero1)  # 添加一个, 同时会把关联的cate对象插入cate_t表
        session.add_all([hero2, hero3])  # 添加多个
        # 提交数据
        session.commit()
        # 查看提交后的变量
        print(hero1)
        print(f"heros: {[hero1, hero2, hero3]}")  # 数据库创建的id会更新到对象中

        # 强制加载数据库中的数据,以更新对象数据
        session.refresh(hero1)  # 并发修改db后,需要更新
        session.refresh(hero2)
        session.refresh(hero3)


        # 查询类别,并关联出该类别的所有的英雄
        cate_ = session.get(Cate, 1) # 查询id=1的类别
        print(f"cate: {cate_} - {cate_.heros}")

        # 查询一个英雄
        statement = select(Hero).where(Hero.name=="寒冰射手").offset(0).limit(1)  # 查询并分页
        # 执行声明语句
        hero_ = session.exec(statement).first()  # .one()/.first()/.all()
        print("hero_:", hero_, hero_.cate, hero_.cate_id)

        # 联合查询
        statement2 = select(Hero, Cate).where(Hero.cate_id == Cate.id).offset(0).limit(10)
        results = session.exec(statement2).all()
        print("results:", results)

        # 继续执行生成器里yield后的逻辑,抛出异常
        next(generator)
    except StopIteration:
        print("执行结束...")


if __name__ == "__main__":
    main()
相关推荐
laufing3 天前
sqlmodel -- fastapi 连接关系型数据库
数据库·fastapi·sqlmodel
予早1 年前
SQLModel入门
数据库·orm·sqlmodel
laufing2 年前
python sqlalchemy(ORM)- 02 表关系
orm·表关系·模型类关系