执行三向连接

时间:2015-10-28 15:02:23

标签: python sqlalchemy

我有三个相关的实体如下:

  • 城堡:属于玩家
  • 玩家:是联盟成员

这些是我的模特:

def ReferenceCol(tablename, nullable=False, pk_name='id', **kwargs):
    """Column that adds primary key foreign key reference.

    Usage: ::

        category_id = ReferenceCol('category')
        category = relationship('Category', backref='categories')
    """
    return db.Column(
        db.ForeignKey("{0}.{1}".format(tablename, pk_name)),
        nullable=nullable, **kwargs)

class Player(Model):

    __tablename__ = 'players'
    id = Column(db.Integer, primary_key=True)
    player_name = Column(db.String(80), unique=False, nullable=False)
    alliance_id = ReferenceCol('alliances', nullable=True)
    ...
    def __repr__(self):
        return '<Player({player_name!r})>'.format(player_name=self.player_name)


class Alliance(Model):

    __tablename__ = 'alliances'
    id = Column(db.Integer, primary_key=True)
    alliance_name = Column(db.String(80), unique=False, nullable=False)
    ...
    def __repr__(self):
        return '<Alliance({alliance_name!r})>'.format(alliance_name=self.alliance_name)


class Habitat(Model):

    __tablename__ = 'habitats'
    id = Column(db.Integer, primary_key=True)
    castle_name = Column(db.String(80), unique=False, nullable=True)
    player_id = ReferenceCol('players', nullable=True)
    ...
    def __repr__(self):
        return '<Habitat({castle_name!r})>'.format(castle_name=self.castle_name)

我可以轻松加入habiats和玩家:

# Join habitats and players
for habitat, player in db.session.query(Habitat, Player).join(Player).all()[:3]:
    print habitat, player

球员和联盟:

# Join players and alliances
for player, alliance in db.session.query(Player, Alliance).join(Alliance).all()[:3]:
    print player, alliance

但如何加入所有三个表?我怎样才能加入栖息地,球员和联盟?我正在寻找可以做的事情:

for castle, player, alliance in magic_join():
    print castle, player, alliance

1 个答案:

答案 0 :(得分:4)

您可以将多个模型传递给join。订单很重要:如果您查询Habitat,您只会获得与玩家有栖息地和联盟的玩家。如果您使用外部联接查询Alliance,那么您将获得与其玩家及其栖息地的所有联盟。

for a, p, h in session.query(Alliance, Player, Habitat).outerjoin(Player, Habitat):
    print(a.id, p.id, h.id)

不是查询多个对象,而是定义relationships。查询Alliance并使用eager loading加载关系而无需额外查询。迭代联盟,并为每个联盟迭代其玩家等等。

class Alliance(Base):
    __tablename__ = 'alliance'
    id = sa.Column(sa.Integer, primary_key=True)

class Player(Base):
    __tablename__ = 'player'
    id = sa.Column(sa.Integer, primary_key=True)
    alliance_id = sa.Column(sa.ForeignKey(Alliance.id), nullable=False)
    alliance = orm.relationship(Alliance, backref='players')

class Habitat(Base):
    __tablename__ = 'habitat'
    id = sa.Column(sa.Integer, primary_key=True)
    player_id = sa.Column(sa.ForeignKey(Player.id), nullable=False)
    player = orm.relationship(Player, backref='habitats')
for a in session.query(Alliance).options(
    db.joinedload(Alliance.players).joinedload(Player.habitats)
):
    for p in a.players:
        for h in p.habitats:
            print(a.id, p.id, h.id)