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

时间:2017-01-25 10:55:28

标签: python python-3.x sqlalchemy relationship

我有一个Player课程,每个玩家拥有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无法区分这两个列表。我该如何启用此类行为?

1 个答案:

答案 0 :(得分:2)

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

这是一个愚蠢但有效的例子(忽略了gobbledygook与会话等,我只是在一段旧代码上复制了一个新模型)如果我理解你的问题是正确的。它将创建一个模型,插入一个玩家,一个活着的角色和一个死角色,然后显示它们。这是你在找什么?

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