两个相同的两个模型之间的一对多关系

Two one-to-many relationships between the same two models

我有一个 Player class 并且每个玩家拥有 X 数量的 Character 个实例:

class Player(Model):
    characters = relationship('Character', back_populates='owner')

class Character(Model):
    owner = relationship('Player', back_populates='characters')
    owner_id = Column('player_id', Integer, ForeignKey('player.id'))

但现在我想将这些字符分成两个单独的列表,分别在 graveyard 和正常的 characters 列表中:

class Player(Model):
    characters = relationship('Character', back_populates='owner')
    graveyard = relationship('Character', back_populates='owner')

class Character(Model):
    owner = relationship('Player', back_populates='characters')
    owner_id = Column('player_id', Integer, ForeignKey('player.id'))

但是如您所见,SQLAlchemy 无法区分这两个列表。我怎样才能启用这种行为?

我大胆假设有一种方法可以区分角色是否在墓地。否则这将没有意义。如果 "Character" table 包含有关字符位置的信息,那么您需要的是 "alternate join" ,如下所述:http://docs.sqlalchemy.org/en/latest/orm/join_conditions.html#specifying-alternate-join-conditions

如果我理解你的问题,这是一个愚蠢但有效的例子(忽略带有会话等的官方文章,我只是在一段旧代码上复制粘贴了一个新模型)。它将创建一个模型,插入一个玩家,一个活着的和一个死去的角色,然后显示它们。这是您要找的吗?

from sqlalchemy import Integer, ForeignKey, String, Column, Boolean, create_engine
from sqlalchemy.orm import sessionmaker, scoped_session
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.exc import IntegrityError
from sqlalchemy.orm import relationship

Base = declarative_base()

engine = create_engine("postgresql://test:test@localhost/test", echo=False)
session_factory = sessionmaker(bind=engine)
Session = scoped_session(session_factory)


class Player(Base):
    __tablename__ = 'player'
    id = Column(Integer, primary_key=True)
    name = Column(String, unique=True)
    characters = relationship('Character', primaryjoin="and_(Character.player_id == Player.id, \
                              Character.alive == True)")
    graveyard = relationship('Character', primaryjoin="and_(Character.player_id == Player.id, \
                              Character.alive == False)")


class Character(Base):
    __tablename__ = 'character'
    id = Column(Integer, primary_key=True)
    name = Column(String, unique=True)
    alive = Column(Boolean)
    player_id = Column(Integer, ForeignKey('player.id'))


Base.metadata.create_all(engine)

try:
    p = Player(name="foo")
    Session.add(p)
    Session.commit()
except IntegrityError:
    Session.rollback()

try:
    p = Session.query(Player).filter(Player.name == "foo").one()
    c1 = Character(name="c1", alive=True, player_id=p.id)
    c2 = Character(name="c2", alive=False, player_id=p.id)
    Session.add(c1)
    Session.add(c2)
    Session.commit()
except IntegrityError:
    Session.rollback()

player = Session.query(Player).filter(Player.name == "foo").one()

print player
for c in player.characters:
    print c.name

for c in player.graveyard:
    print c.name