Reputation: 21883
I have a Player
class and each player owns X amount of Character
instances:
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'))
But now I want to split these characters into two separate lists, ones which are in the graveyard
and the normal characters
list:
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'))
But as you can see, there's no way for SQLAlchemy to differentiate between the two lists. How can I enable such behaviour?
Upvotes: 2
Views: 477
Reputation: 12205
I make a bold assumption there is a way to distinguish whether a character is in graveyard or not. Otherwise this would make no sense. If "Character" table contains information about the location of the character, then what you need is "alternate join" as described here: http://docs.sqlalchemy.org/en/latest/orm/join_conditions.html#specifying-alternate-join-conditions
Here is a silly but working example (ignore the gobbledygook with sessions etc, I just copypasted a new model on piece of old code) if I understood your problem right. It will create a model, insert a player, one alive and one dead character and then display them. Is this what you are looking for?
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
Upvotes: 2