两个相同的两个模型之间的一对多关系
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
我有一个 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