【问题标题】:Cannot properly update SQLAlchemy row无法正确更新 SQLAlchemy 行
【发布时间】:2018-01-08 19:29:28
【问题描述】:

我正在使用 sqlalchemy 范围会话,无法正确更新现有行。

这是我的模型:

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)

我已经填充了数据库,可以看到 Song 行的所有列都在调试器和 pgweb 界面中填充了数据。在视图中,我进行查询以获取歌曲列表并希望按如下方式更新它们:

# 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

这会将 preview_url 添加到一行,但是,一旦我这样做并提交,即使我更新了完全不同的字段,艺术家.id 在歌曲实例中也会变为 None。我可以在调试器和 pgweb 界面中观察到这一点。

更新:我在对行进行任何更改之前尝试了db.commit(),它仍然用None 替换song.artist_id。这意味着行更新与此无关,因此它必须是我在song 上所做的预处理。有什么方法可以在更新和提交行之前摆脱会话中的所有更改?

有没有人遇到过这种行为?我是否必须再次显式设置 artist.id,因为它是外键?

【问题讨论】:

  • 不,您不需要再次指定artist.id。数据是否成功更新/提交到数据库中?
  • 请提供minimal reproducible example。你提到了一些“预处理”。也包括在内。

标签: python sqlalchemy pyramid


【解决方案1】:

我设法找到了这种可疑的行为。问题确实出在预处理上。

很快,我从列表中的许多艺术家那里汇总了Artist.songs,后来我从这个列表中弹出,但是我忘记了这个列表是特殊的,即它是 SQLAlchemy 中的一个仪表化集合,根据文档:

“仪表化意味着对集合的正常操作进行跟踪,并导致在刷新时将更改写入数据库。”

通过从这个集合中弹出,我实际上删除了Artist-Song 关系,因此外键变成了None

我的示例代码看起来像这样:

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

【讨论】:

    猜你喜欢
    • 2017-07-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-01-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-20
    相关资源
    最近更新 更多