2017-05-24 1 views
0

Angenommen, ich habe eine Reihe von Benutzern, eine Reihe von Spielen, und ich verfolgen, ob ein Benutzer ein Spiel in einer separaten Tabelle beendet hat (Name: 'game_progress'). Ich möchte, dass, wann immer ein Benutzer erstellt wird, die Tabelle "game_progress" automatisch mit ihrer ID und einem "Nein" gegen alle verfügbaren Spiele gefüllt wird. (Ich weiß, dass ich warten kann, bis sie ein Spiel startet, um die Platte zu erstellen, aber ich brauche das für einen ganz anderen Zweck.) Wie würde ich das machen?Benutzerdefinierte Operationen beim Erstellen eines SQLAlchemy-Objekts

Ich versuchte mit dem Ereignis after_insert(). Aber, dann kann ich die ID des Benutzers, die in "game_progress" eingefügt werden soll, nicht abrufen. Ich möchte after_flush nicht verwenden (auch wenn ich herausfinden kann, wie es geht), weil es vielleicht ein bisschen Overkill ist, da die Benutzererstellungsoperation nicht so häufig vorkommt.

class Game(db.Model): 

    __tablename__ = 'games' 
    id = db.Column(db.Integer, primary_key=True) 
    name = db.Column(db.Unicode(30)) 

class User(db.Model): 

    __tablename__ = 'users' 
    id = db.Column(db.Integer, primary_key=True) 
    name = db.Column(db.Unicode(30)) 

class GameProgress(db.Model): 

    __tablename__ = 'game_progress' 
    user_id = db.Column(db.Integer, db.ForeignKey('users.id'), primary_key=True) 
    game_id = db.Column(db.Integer, db.ForeignKey('games.id'), primary_key=True) 
    game_finished = db.Column(db.Boolean) 

@event.listens_for(User, "after_insert") 
def after_insert(mapper, connection, target): 
    progress_table = GameProgress.__table__ 
    user_id = target.id 
    connection.execute(
     progress_table.insert().\ 
      values(user_id=user_id, game_id=1, game_finished=0) 
    ) 

db.create_all() 
game = Game(name='Solitaire') 
db.session.add(game) 
db.session.commit() 
user = User(name='Alice') 
db.session.add(user) 
db.session.commit() 
+0

Normalerweise würden Sie DB-Trigger für solche verwenden, oder einfach die Erstellung der erforderlichen zusätzlichen Daten in Ihre Logik des Erstellens eines neuen Benutzers einschließen, was bedeutet, dass Sie eine Funktion schreiben, die das Erstellen von Benutzern handhabt. –

Antwort

0

Sie brauchen nichts zu tun Phantasie mit Triggern oder gar Event-Listener, können Sie nur die Beziehungen aufgebaut und dann verwandte Objekte im Konstruktor für Benutzer machen. Solange Sie Beziehungen definiert haben (die Sie derzeit nicht ausführen, haben Sie nur die Fremdschlüssel hinzugefügt), benötigen Sie keine Benutzer-ID, um die zugehörigen Objekte einzurichten. Ihr Konstruktor kann nur etwas tun, wie folgt aus:

class User(db.Model): def __init__(self, all_games, **kwargs): for k,v in kwargs.items(): setattr(self, k, v) for game in all_games: self.game_progresses.append(GameProgress(game=game, \ user=self, game_finished=False))

Wenn Sie den Benutzer begehen, werden Sie auch eine Liste der Objekte GameProgress verpflichten, eine für jedes Spiel. Das Obige hängt jedoch davon ab, dass Sie Beziehungen für alle Ihre Objekte einrichten. Sie müssen die unten an GameProgress Klasse

game = relationship("Game", backref="game_progresses") user = relationship("User", backref="game_progresses")

Und passieren in einer Liste der Spiele zu Benutzer hinzufügen, wenn Sie Ihren Benutzer machen:

all_games = dbs.query(Game).all() new_user = User(all_games=all_games, name="Iain")

Sobald das erledigt ist können Sie einfach GameProgress hinzufügen Objekte zu der instrumentierten Liste user.game_progresses und Sie müssen vor dem ersten Commit nichts festgelegt haben. SQLA wird alle Beziehungen verfolgen. Grundsätzlich müssen Sie sich immer dann fragen, wenn Sie direkt mit einer ID arbeiten: Wenn Sie das ORM-Recht verwenden, müssen Sie das selten tun. Das ORM-Tutorial zu den SQLA-Dokumenten geht das sehr gut durch. Es gibt viele Optionen, die Sie an Beziehungen und Backrefs übergeben können, damit das Cascading funktioniert.

+0

Perfekt. "Immer wenn du direkt mit einer ID meckern musst, frage dich, ob du das ORM richtig verwendest." Wird das bedenken. Vielen Dank! – contrariwise

Verwandte Themen