如何在一个提交中使用SQLAlchemy交换唯一行的两个字段?
假设你有一个对象,它的名字是独一无二的。现在你想要交换两个对象的名字:
这里是布局:
import sqlalchemy as sa
import sqlalchemy.orm as orm
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
class MyObject(Base):
__tablename__ = 'my_objects'
id = sa.Column(sa.Integer, primary_key=True)
name = sa.Column(sa.Text, unique=True)
if __name__ == "__main__":
engine = sa.create_engine('sqlite:///:memory:', echo=True)
Session = orm.sessionmaker(bind=engine)
Base.metadata.create_all(engine)
session = Session()
我想要这样做:
a = MyObject(name="Max")
b = MyObject(name="Moritz")
session.add_all([a, b])
session.commit()
# Now: switch names!
tmp = a.name
a.name = b.name
b.name = tmp
session.commit()
这样做会出现一个叫做 IntegrityError
的错误。有没有办法在一次提交中交换这些字段,而不出现这个错误呢?
4 个回答
0
Python 允许使用这种语法(用元组):
a.name, b.name = b.name, a.name
这样交换两个普通参数是完全可以的,不过在你的情况下没有经过测试,或许你可以试试看?
5
一个更简单的方法是先删除a,然后把b改个名字,最后再把a以新名字加回来:
session.delete(a)
sqlalchemy.orm.session.make_transient(a)
a.name, b.name = b.name, a.name
session.flush()
session.add(a)
session.commit()
4
你在名字字段里设置了 unique=True
,这意味着每个名字都必须是唯一的。所以当你尝试提交的时候,它会执行更新操作,这时就会出现错误。
具体来说,当你修改名字时,这个新名字会先在内存中被记录下来。但是当系统尝试执行更新操作时,发现数据库里已经有一个相同名字的记录了,因此就会报 IntegrityError
的错误。
要更改名字的方法是
a = MyObject(name="Max")
b = MyObject(name="Moritz")
session.add_all([a, b])
session.commit()
# Now: switch names!
atmp = a.name
btemp = b.name
a.name = a.name+btemp # Temp set the any random name
session.commit()
b.name = atemp
a.name = btemp
session.commit() # Run the update query for update the record.