如何使用 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
。有没有一种方法可以在一次提交内切换这些字段而不会出现此错误?
Assume to have a object with unique name. Now you want to switch the name of two objects:
Here is the layout:
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()
And I would like to do this:
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()
This throws an IntegrityError
. Is there a way to switch these fields within one commit without this error?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
更纯粹的选择是删除 a,重命名 b,然后重新添加重命名的:
A more pure option would be to delete a, rename b, then re-add a renamed:
您在名称字段中给出了
unique=True
,因此当您尝试提交时,它将运行更新查询,从而引发错误。情况是当您更改名称时,它将在内存中设置。但是,当它尝试运行更新查询时,旧记录已存在同名,因此它将给出
IntegrityError
。改名的方法是
You gave
unique=True
in the name field so when you are trying to commit it will run the update query it will raise the error.The situation is when you change the name it will set in memory. But when it will try to run the update query the old record already exist with same name so it will give the
IntegrityError
.The way to change name is
Python允许这种语法(使用元组):
以这种方式切换两个普通参数是绝对可以的,但没有在你的情况下进行测试,也许你可以尝试一下?
Python allows this syntax(using tuples):
It's absolutely okay to switch two normal arguments this way, but not tested in your situation, maybe you can give it a try?
感谢 Philipp der Rautenberg 的评论 我找到了更好的解决方案,可以与 PostgreSQL 一起使用,但不能SQLite。
有关其工作原理的更多信息,请参阅此答案和PostgreSQL 文档 和 SQLAlchemy 文档。
这个想法是首先将唯一约束声明为
deferrable
,然后通过在initially
: 中使用它或使用显式 sql 语句将其设置为
DEFERRED
:或者
但请记住在使用
SET CONSTRAINTS
时:Thanks to Philipp der Rautenberg's comment I found nicer solution which works with PostgreSQL, but not SQLite.
More information on how it works is in this answer and in PostgreSQL docs and in SQLAlchemy docs.
The idea is to first declare unique constraint as
deferrable
and then set it asDEFERRED
either by using it ininitially
:or with explicit sql statement:
or
but remember when using
SET CONSTRAINTS
that: