2017-08-01 3 views
0

Je travaille avec la session étendue sqlalchemy et je ne peux pas mettre à jour correctement une ligne existante.Impossible de mettre à jour correctement la ligne SQLAlchemy

Voici mes modèles:

db = scoped_session(sessionmaker()) 
Base = declarative_base() 

class Song(Base): 
    __tablename__ = 'song' 
    id = Column(Integer, primary_key=True) 
    artist_id = Column(Integer, ForeignKey('artist.id')) 
    artist_title = Column(Text) 
    title = Column(Text) 
    artist = relationship('Artist', backref='songs') 
    preview_url = Column(Text, default=None) 


class Artist(Base): 
    __tablename__ = 'artist' 
    id = Column(Integer, primary_key=True) 
    title = Column(Text) 

    similar_artists = relationship('Artist', 
            secondary=followers, 
            primaryjoin=(followers.c.follower_id == id), 
            secondaryjoin=(followers.c.followed_id == id), 
            backref=backref('followers', lazy='dynamic'), 
            lazy='dynamic') 

Index('my_index', Artist.id, unique=True, mysql_length=255) 

J'ai peuplé la db et peut voir que les lignes de morceau ont toutes les colonnes remplies de données dans le débogueur et aussi l'interface pgweb. Dans les vues que je fais une requête pour obtenir une liste de chansons et que vous souhaitez les mettre à jour comme suit:

# song.artist_id has an integer value 
song.preview_url = preview_url # Just a string 
# db.query(Song).filter(Song.id == song.id).update({'preview_url':preview_url}) #Produces same result as above 

db.commit() 
# song.artist_id becomes None 

Cela ajoute la preview_url à une ligne, cependant, une fois que je fais cela et engage le artist.id devient Aucun dans l'instance de la chanson, même si je mettais à jour un champ complètement différent. Je peux observer cela dans l'interface debugger et pgweb.

MISE À JOUR: J'ai essayé db.commit() juste avant que je ne les modifications à la ligne et il remplace encore song.artist_id avec None. Cela implique que la mise à jour de ligne n'a rien à voir avec cela, par conséquent, il doit être pré-traitement que je fais sur song. Est-il possible de me débarrasser de tous les changements dans la session avant de mettre à jour et de valider la ligne?

Est-ce que quelqu'un a rencontré ce comportement? Dois-je redéfinir explicitement artist.id car c'est une clé étrangère?

+0

Non, vous n'avez pas besoin de préciser à nouveau la artist.id. Les données ont-elles été mises à jour/validées avec succès dans la base de données? – ionheart

+1

Veuillez fournir un [mcve]. Vous parlez de "pré-traitement". Incluez cela aussi. –

Répondre

0

J'ai réussi à localiser ce comportement de poisson. Le problème était en effet avec le pré-traitement. Peu de temps, je regroupais Artist.songs de nombreux artistes dans une liste et plus tard, je sortais de cette liste, mais ce que j'ai oublié, c'est que cette liste est spéciale, c'est à dire c'est une collection Instrumented dans SQLAlchemy, qui selon les docs :

«Instrumentation signifie que les opérations normales sur la collecte sont suivies et entraînent des modifications en cours d'écriture à la base de données au moment flush »

en sautant de cette collection, je supprimait effectivement Artist - Song relations, donc la clé étrangère devenait None.

Mon code d'échantillon avait l'air quelque chose comme ça:

artists = db.query(Artist).all() 
all_songs = [] 
for artist in artists: 
    all_songs.append(artist.songs) 

all_songs.pop(0) # This would delete the Artist-Song relation after the commit