首页 > 解决方案 > SQL Alchemy:3 个表之间的关系(间接)

问题描述

我正在构建一个 api(使用 SQLAchemy 和 FastApi,将使用 postgresql,现在它是一个 sqlite 文件)。我关心的问题 3 类:第一个是Game,对于每场比赛,我在PlayerStat中有 10 个玩家(与 match_id 的关系),每个玩家扮演一个独特的英雄(所以主键是 match_id 和 hero_id)。每个玩家可以有 5 个项目(可以相同或不同)。最后一个类是ItemInfo,关于一个特定项目的信息取决于游戏补丁(存储在 Game 中)和玩家的 item_id(存储在 PlayerStat 中)。我想根据 Game.patch 和不同的 PlayerStat.item_0、PlayerStat.item_1 加载 10 个玩家(5 个项目 * 10 个玩家)的所有项目的项目信息 ...

我成功加入了与 PlayerStat.hero_id 相关的第 4 类 HeroInfo(与 Game.patch 无关),同样的想法但更容易,因为它们只有一个子句。

这是我的模型:

class HeroInfo(Base):
    __tablename__ = "herosinfos"

    id = Column(Integer, primary_key=True)
    name = Column(String)

    playerstats = relationship("PlayerStat", back_populates="heroinfos")


class ItemInfo(Base):
    __tablename__ = "itemsinfos"

    id = Column(Integer, primary_key=True)
    name = Column(String)
    patch = Column(Integer, primary_key=True)

    playerstats = relationship("PlayerStat", back_populates="itemsinfos")
    game = relationship("Game", back_populates="itemsinfos")


class PlayerStat(Base):
    __tablename__ = "playerstats"

    match_id = Column(Integer, ForeignKey("games.id"), primary_key=True)
    slot = Column(Integer, primary_key=True)
    hero_id = Column(Integer, ForeignKey("herosinfos.id"), primary_key=True)
    num_kills = Column(Integer, default=None)
    is_teamA = Column(Boolean, default=None)
    item_0 = Column(Integer, ForeignKey("itemsinfos.id"))
    item_1 = Column(Integer, ForeignKey("itemsinfos_1 .id"))
    item_2 = Column(Integer, ForeignKey("itemsinfos_1 .id"))
    item_3 = Column(Integer, ForeignKey("itemsinfos_1 .id"))
    item_4 = Column(Integer, ForeignKey("itemsinfos_1 .id"))

    game = relationship("Game", back_populates="playerstats")
    heroinfos = relationship("HeroInfo", back_populates="playerstats")
    itemsinfos = relationship("ItemInfo", back_populates="playerstats")
    itemsinfos_1 = relationship("ItemInfo", back_populates="playerstats")
    itemsinfos_2 = relationship("ItemInfo", back_populates="playerstats")
    itemsinfos_3 = relationship("ItemInfo", back_populates="playerstats")
    itemsinfos_4 = relationship("ItemInfo", back_populates="playerstats")


class Game(Base):
    __tablename__ = "games"

    id = Column(Integer, primary_key=True, index=True)
    league_id = Column(Integer)
    patch = Column(Integer, ForeignKey("itemsinfos.patch"))
    teamA_score = Column(Integer)
    teamB_score = Column(Integer)
    duration = Column(Integer)

    playerstats = relationship("PlayerStat", back_populates="game", lazy="joined", order_by='asc(PlayerStat.slot)')
    itemsinfos = relationship("ItemInfo", back_populates="game")
    itemsinfos_1 = relationship("ItemInfo", back_populates="game")
    itemsinfos_2 = relationship("ItemInfo", back_populates="game")
    itemsinfos_3 = relationship("ItemInfo", back_populates="game")
    itemsinfos_4 = relationship("ItemInfo", back_populates="game")

我假设我需要为这个表写 5 倍的关系(ItemInfo -> PlayerStat 和 ItemInfo -> Game)?我写的最接近我想要的结果的请求是:

data = session.query(models.Game).filter(models.Game.id == match_id).\
    join(models.PlayerStat).\
    options(joinedload(models.Game.playerstats).selectinload(models.PlayerStat.heroinfos)).\
    join(models.ItemInfo, and_(models.PlayerStat.item_0 == models.ItemInfo.id, models.Game.patch==models.ItemInfo.patch), isouter=True).\
    options(contains_eager(models.Game.itemsinfos)).one()

但架构是: 实际数据结构(itemsinfos 不正确

我想拥有 :想要的数据结构

我对 models.ItemInfo 做错了,但不知道如何用 sqlAlchemy 编写它!

希望我正确解释了我想做什么,所以你可以帮助我!谢谢阅读。

标签: pythonsqldatabasesqlalchemy

解决方案


推荐阅读