插入SQL炼金术中忽略的辅助连接条件

时间:2015-02-13 19:50:36

标签: python sqlalchemy flask-sqlalchemy

我有以下模型(我还需要添加一些适当的验证):

class Participant(db.Model):
    player_id = db.Column(db.Integer, db.ForeignKey('player.id'),
                          primary_key=True)
    game_id = db.Column(db.Integer, db.ForeignKey('game.id'), primary_key=True)
    winner = db.Column(db.Boolean)


class Player(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(64), index=True, unique=True)
    email = db.Column(db.String(120), index=True, unique=True)
    avatar = db.Column(db.String(120))
    skill = db.Column(db.Integer)


def __repr__(self):
        return '<User %r>' % (self.name)


class Game(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    date = db.Column(db.DateTime, default=datetime.datetime.utcnow)
    loser_score = db.Column(db.Integer)
    loser = db.relationship('Player',
                              secondary=Participant.__table__,
                              secondaryjoin=and_(
                                 Player.id == Participant.player_id,
                                 Participant.winner == False))
    winner = db.relationship('Player',
                             secondary=Participant.__table__,
                             secondaryjoin=and_(
                                 Player.id == Participant.player_id,
                                 Participant.winner == True))

    def __repr__(self):
        return '<Game %r>' % (self.id)

当我检索数据时,这些功能很棒。当我插入一个Game对象时,它会忽略“赢家”。参与者表中的字段并生成以下SQL语句:

INFO:sqlalchemy.engine.base.Engine:
INSERT INTO game (date, loser_score) VALUES (?, ?)
('2015-02-13 19:31:04.804182', 15)
INSERT INTO participant (player_id, game_id) VALUES (?, ?)
(2, 2)
INSERT INTO participant (player_id, game_id) VALUES (?, ?)
(1, 2)

我希望它会产生:

INFO:sqlalchemy.engine.base.Engine:
INSERT INTO game (date, loser_score) VALUES (?, ?)
('2015-02-13 19:31:04.804182', 15)
INSERT INTO participant (player_id, game_id, winner) VALUES (?, ?, 0)
(2, 2)
INSERT INTO participant (player_id, game_id, winner) VALUES (?, ?, 1)
(1, 2)

有谁知道为什么会这样?

1 个答案:

答案 0 :(得分:0)

你不能sqlalchemy能够处理开箱即用的案件。下面的代码是我在这种情况下使用的代码:

class Player(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(64), index=True, unique=True)
    email = db.Column(db.String(120), index=True, unique=True)
    avatar = db.Column(db.String(120))
    skill = db.Column(db.Integer)


class Participant(db.Model):
    player_id = db.Column(db.Integer, db.ForeignKey('player.id'),
                          primary_key=True)
    game_id = db.Column(db.Integer, db.ForeignKey('game.id'), primary_key=True)
    winner = db.Column(db.Boolean)

    # relationships
    player = db.relationship('Player')


class Game(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    date = db.Column(db.DateTime, default=datetime.datetime.utcnow)
    loser_score = db.Column(db.Integer)

    # relationships
    game_players = db.relationship(
        'Participant',
        collection_class=attribute_mapped_collection("winner"),
        cascade="all, delete-orphan",
        backref="game",
    )

    # this allows usage like: my_game.player[True/False] = my_player
    players = association_proxy(
        'game_players', 'player',
        creator=lambda win, pla: Participant(winner=win, player=pla),
    )

    # winner: an alias to self.players[True]
    @property
    def winner(self):
        return self.players.get(True)

    @winner.setter
    def winner(self, value):
        self.players[True] = value

    @winner.deleter
    def winner(self):
        del self.players[True]

    # loser: an alias to self.players[False]
    @property
    def loser(self):
        return self.players.get(False)

    @loser.setter
    def loser(self, value):
        self.players[False] = value

    @loser.deleter
    def loser(self):
        del self.players[False]

允许您使用如下代码:

g1 = Game(...)
g1.players[True] = playerA
g1.players[False] = playerB

并且属性获胜者/输家甚至喜欢:

g1 = Game(...)
g1.winner = playerA
g1.loser = playerB

有关attribute_mapped_collection及其用法的更多信息,请阅读Proxying to Dictionary Based Collections