【问题标题】:SQLAlchemy insert or update exampleSQLAlchemy 插入或更新示例
【发布时间】:2011-12-14 21:47:21
【问题描述】:

在 Python 中,我想使用 SQLAlchemy 插入或更新一行。我试过这个:

existing = db.session.query(Toner)
for row in data:
    new = Toner(row[0], row[1], row[2])

它不起作用。如何将new 插入或更新到Toner 表中?我怀疑它是通过合并完成的,但我不明白该怎么做。

【问题讨论】:

  • (标准)SQL 中没有插入或更新。您必须手动获取和更新现有对象,然后插入那些尚不存在的对象。或者,您将不得不回避 ORM 并手动发出依赖于后端的 SQL。
  • @Ferdinand Beyer session.merge() (sqlalchemy.org/docs/orm/session.html#merging) 不适合我吗?
  • session.merge() 做了一些完全不同的事情:它将一个源自另一个会话的对象添加到会话中。例如,如果有一个 ID 为 42 的对象,session.merge() 将从数据库中获取 ID 为 42 的行,并返回一个表示同一数据库行的新对象。这与INSERTUPDATE 无关。
  • 您的示例代码令人困惑:它显示您从数据库中检索Toner 对象,这意味着它们已经存在;然后您尝试使用相同的字段再次创建 Toner 对象。请将您的示例扩展为更现实的示例。
  • 您能否更改已接受的答案,因为它只有反对票并且您对它的评论表明它对您没有帮助?

标签: python sqlalchemy


【解决方案1】:

我尝试了很多方法,最后尝试了这个:

def db_persist(func):
    def persist(*args, **kwargs):
        func(*args, **kwargs)
        try:
            session.commit()
            logger.info("success calling db func: " + func.__name__)
            return True
        except SQLAlchemyError as e:
            logger.error(e.args)
            session.rollback()
            return False
        finally:
            session.close()

    return persist

和:

@db_persist
def insert_or_update(table_object):
    return session.merge(table_object)

【讨论】:

  • 您可以/应该在 try-catch 的 finally 块中添加 session.close()
【解决方案2】:

插入 .. 重复密钥更新 ..

sql:

INSERT INTO the_table (id, col1) VALUES (%s, %s) 
   ON DUPLICATE KEY UPDATE col1 = %s

在py代码中:
// 使用 sqlalchemy 1.4.x 进行测试,使用 mysql

def test_insert_or_update():
    insert_stmt = insert(the_table).values(
        id = 'xxx',
        col1 = 'insert value',
    )
    on_duplicate_key_stmt = insert_stmt.on_duplicate_key_update(
        # col1 = insert_stmt.inserted.data,
        col1 = 'update value',
        col2 = 'mark'
    )
    print(on_duplicate_key_stmt)
    session.execute(on_duplicate_key_stmt)
    session.commit()

【讨论】:

    【解决方案3】:

    假设某些列名...

    插入一个

    newToner = Toner(toner_id = 1,
                        toner_color = 'blue',
                        toner_hex = '#0F85FF')
    
    dbsession.add(newToner)   
    dbsession.commit()
    

    插入多个

    newToner1 = Toner(toner_id = 1,
                        toner_color = 'blue',
                        toner_hex = '#0F85FF')
    
    newToner2 = Toner(toner_id = 2,
                        toner_color = 'red',
                        toner_hex = '#F01731')
    
    dbsession.add_all([newToner1, newToner2])   
    dbsession.commit()
    

    更新

    q = dbsession.query(Toner)
    q = q.filter(Toner.toner_id==1)
    record = q.one()
    record.toner_color = 'Azure Radiance'
    
    dbsession.commit()
    

    或使用MERGE 使用花哨的单线器

    record = dbsession.merge(Toner( **kwargs))
    

    【讨论】:

    • dbsession 来自哪里? O.o 是来自create_engine() 吗?
    • 所以如果有人想知道dbsession 来自哪里,它可能来自Session(),或者如果你有带有预配置的会话工厂,比如MySession = sessionmaker(create_engine(...)) 然后MySession() 来创建这个dbsession
    • 更新代码会得到:sqlalchemy.exc.InvalidRequestError: No transaction is started.
    • merge 是否接受对象或映射列表?
    猜你喜欢
    • 1970-01-01
    • 2014-08-08
    • 1970-01-01
    • 2012-07-02
    • 2018-08-01
    • 2014-02-08
    • 2021-07-19
    • 2017-05-30
    • 2016-05-02
    相关资源
    最近更新 更多