【问题标题】:SQLAlchemy relationships to same tableSQLAlchemy 与同一张表的关系
【发布时间】:2016-01-26 02:46:57
【问题描述】:

我已经声明了以下模型:

from sqlalchemy import (
    Column,
    Table,
    Integer,
    Date,
    String,
    ForeignKey,
)

from sqlalchemy import create_engine

from sqlalchemy.orm import sessionmaker

from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.ext.associationproxy import association_proxy

from sqlalchemy.orm import relationship, backref

engine = create_engine('sqlite:///data.sqlite')
DBSession = sessionmaker(bind=engine)

Base = declarative_base()


lineup = Table('lineups', Base.metadata,
               Column('match_id', Integer, ForeignKey('data.id')),
               Column('player_id', Integer, ForeignKey('players.id')))


class Match(Base):
    __tablename__ = 'data'

    id = Column(Integer, primary_key=True)
    date = Column(Date)
    tournament = Column(String)
    team1 = Column(String)
    team2 = Column(String)
    team1_lineup = relationship('Player', secondary=lineup)
    team2_lineup = relationship('Player', secondary=lineup)
    best_of = Column(Integer)
    maps = relationship('Map')
    score = Column(String)


class Map(Base):
    __tablename__ = 'maps'

    id = Column(Integer, primary_key=True)
    match = Column(Integer, ForeignKey('data.id'))
    name = Column(String)
    score = Column(String)


class Player(Base):
    __tablename__ = 'players'

    id = Column(Integer, primary_key=True)
    nickname = Column(String)
    team = Column(String)

我正在以这种方式创建新的Match 对象:

match = Match(...) # all kwargs except team1_lineup and team2_lineup

p1 = Player(id=1, nickname='p1', team='team')
p2 = Player(id=2, nickname='p2', team='team')
p3 = Player(id=3, nickname='p2', team='team')

match.team1_lineup.append(p1)
match.team2_lineup.append(p2)
match.team2_lineup.append(p3)

提交新对象后,我正在查询它。

>>> from hltv.models import Match, DBSession
>>> s = DBSession()
>>> m = s.query(Match).first()
>>> m.team1_lineup
[<hltv.models.Player object at 0x7f1a93009d10>, <hltv.models.Player object at 0x7f1a93009d90>, <hltv.models.Player object at 0x7f1a93009e10>]
>>> m.team2_lineup
[<hltv.models.Player object at 0x7f1a93009d10>, <hltv.models.Player object at 0x7f1a93009d90>, <hltv.models.Player object at 0x7f1a93009e10>]

问题是m.team1_lineupm.team2_lineup 是一样的。我该如何解决这个问题? 另外,如何为每个阵容分配 ID(相同球员的阵容应该有相同的 ID)?

【问题讨论】:

    标签: python sqlite orm sqlalchemy


    【解决方案1】:

    我已经设法解决了我的问题。我必须将 ID 添加到阵容(我已将其重命名为 Team),并通过为这些团队提供两个不同的 ID 来指定如何加入表格。 André 发布的另一种方式解决方案。

    代码如下:

    from sqlalchemy import (
        Column,
        Table,
        Integer,
        Date,
        String,
        ForeignKey,
    )
    
    from sqlalchemy import create_engine
    
    from sqlalchemy.orm import sessionmaker
    
    from sqlalchemy.ext.declarative import declarative_base
    
    from sqlalchemy.orm import relationship, backref
    
    engine = create_engine('sqlite:///data.sqlite')
    DBSession = sessionmaker(bind=engine)
    
    Base = declarative_base()
    
    
    class Match(Base):
        __tablename__ = 'data'
    
        id = Column(Integer, primary_key=True)
        date = Column(Date)
        tournament = Column(String)
        best_of = Column(Integer)
        score = Column(String)
        maps = relationship('Map')
        team1_id = Column(ForeignKey('team.id'))
        team2_id = Column(ForeignKey('team.id'))
    
        team1 = relationship('Team', primaryjoin='Match.team1_id == Team.id')
        team2 = relationship('Team', primaryjoin='Match.team2_id == Team.id')
    
    
    class Map(Base):
        __tablename__ = 'map'
    
        id = Column(Integer, primary_key=True)
        match = Column(Integer, ForeignKey('data.id'))
        name = Column(String)
        score = Column(String)
    
    
    lineup = Table('lineup',
                   Base.metadata,
                   Column('player_id', Integer, ForeignKey('player.id')),
                   Column('team_id', Integer, ForeignKey('team.id')))
    
    
    
    class Player(Base):
        __tablename__ = 'player'
    
        id = Column(Integer, primary_key=True)
        nickname = Column(String)
    
    
    class Team(Base):
        __tablename__ = 'team'
    
        id = Column(Integer, primary_key=True)
        name = Column(String)
    
        players = relationship('Player', secondary=lineup, backref='teams')
    

    【讨论】:

    • 我很高兴为最终解决方案提供帮助。不要忘记将自己的答案设置为已解决。
    【解决方案2】:

    我对人际关系有一些建议:

    • 考虑到每场比赛都有 2(2) 个球队和 2(2) 个不同的阵容,当您对两个不同的阵容使用相同的比赛 id 时,会发生此查询错误以返回阵容;
    • 我不擅长运动,但我认为你可以对模型进行更好的归一化。例如:创建一个新的模型团队

    我的建议是为 Many to many 更改一些模型,如下所示:

    from sqlalchemy import (
        Column,
        Table,
        Integer,
        Date,
        String,
        ForeignKey,
    )
    
    from sqlalchemy import create_engine
    
    from sqlalchemy.orm import sessionmaker
    
    from sqlalchemy.ext.declarative import declarative_base
    from sqlalchemy.ext.associationproxy import association_proxy
    
    from sqlalchemy.orm import relationship, backref
    
    engine = create_engine('sqlite:///data.sqlite')
    DBSession = sessionmaker(bind=engine)
    
    Base = declarative_base()
    
    lineup = Table('lineups', Base.metadata,
                   Column('team_id', Integer, ForeignKey('teams.id')),
                   Column('player_id', Integer, ForeignKey('players.id')))
    
    class Team(Base):
        __tablename__ = 'teams'
        id = Column(Integer, primary_key=True,autoincrement= True)
        name = Column(String)
        team_lineup = relationship('Player',secondary=lineup)
    
    match_team = Table('match_teams', Base.metadata,
                   Column('match_id', Integer, ForeignKey('matches.id')),
                   Column('team_id', Integer, ForeignKey('teams.id')))
    
    class Match(Base):
        __tablename__ = 'matches'
        id = Column(Integer, primary_key=True,autoincrement= True)
        date = Column(Date)
        tournament = Column(String)
        team = relationship('Team',secondary=match_team)
        best_of = Column(Integer)
        maps = relationship('Map')
        score = Column(String)
    
    class Map(Base):
        __tablename__ = 'maps'
        id = Column(Integer, primary_key=True,autoincrement= True)
        match = Column(Integer, ForeignKey('matches.id'))
        name = Column(String)
        score = Column(String)
    
    class Player(Base):
        __tablename__ = 'players'
        id = Column(Integer, primary_key=True,autoincrement= True)
        nickname = Column(String)
    

    创建对象...

    s = DBSession()
    
    Base.metadata.drop_all(engine) 
    Base.metadata.create_all(engine) 
    
    t1 = Team(name="t1")
    t2 = Team(name="t2")
    
    p1 = Player()
    p2 = Player()
    p3 = Player()
    
    s.add(p1)
    s.add(p2)
    s.add(p3)
    
    t1.team_lineup.append(p1)
    t2.team_lineup.append(p2)
    t2.team_lineup.append(p3)
    
    s.add(t1)
    s.add(t2)
    
    m = Match()
    m.tournament="xpto"
    m.team.append(t1)
    m.team.append(t2)
    
    s.add(m)
    s.commit()
    

    然后,你可以看到阵容和你的预期一样:

    >>> m = s.query(Match).first()
    >>> for t in m.team:
    ...     print t.team_lineup
    ... 
    [<__main__.Player object at 0x10b57c890>]
    [<__main__.Player object at 0x10b57c910>, <__main__.Player object at 0x10b57c990>]
    

    在这种情况下,每场比赛您可以有“n”支球队。我不知道在您管理的运动中是否有可能。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-10-06
      • 1970-01-01
      • 1970-01-01
      • 2011-11-24
      • 2020-10-12
      • 2015-12-10
      • 1970-01-01
      相关资源
      最近更新 更多