2015-04-22 69 views
0

我的版本:SQLAlchemy:如何在一次交易中交换唯一值?

$ python 
Python 3.4.0 (default, Apr 11 2014, 13:05:11) 
[GCC 4.8.2] on linux 
Type "help", "copyright", "credits" or "license" for more information. 
>>> import sqlalchemy 
>>> sqlalchemy.__version__ 
'1.0.0' 

让我们看看到例如SQLite的(在生产中我使用MySQL,但是没关系这里):

from sqlalchemy.ext.declarative import declarative_base 
from sqlalchemy.orm import sessionmaker 
from sqlalchemy import Column 
from sqlalchemy import create_engine 
from sqlalchemy import Integer, String 

Base=declarative_base() 
engine = create_engine('sqlite:///:memory:', echo=True) 

class User(Base): 
    __tablename__ = 'user' 
    id  = Column(Integer, primary_key=True) 
    name = Column(String(16)) 
    tech_id = Column(Integer, unique=True, nullable=True) 

Base.metadata.create_all(engine) 

Session = sessionmaker(bind=engine) 
s = Session() 

现在我们添加两个记录:

u1=User(name="User1", tech_id=None) 
u2=User(name="User2", tech_id=10) 
s.add(u1) 
s.add(u2) 
s.commit() 

下一页尝试对其进行修改:

u1=s.query(User).filter(User.name=="User1").first() 
u2=s.query(User).filter(User.name=="User2").first() 

u2.tech_id=None 
u1.tech_id=10 
s.commit() 

提交后,我已经得到了异常:

<-- cut --> 
sqlalchemy.exc.IntegrityError: (sqlite3.IntegrityError) UNIQUE constraint failed: user.tech_id [SQL: 'UPDATE user SET tech_id=? WHERE user.id = ?'] [parameters: ((10, 1), (None, 2))] 

如果我这样做:

u2.tech_id=None 
s.commit() 
u1.tech_id=10 
s.commit() 

它的所有权利。

是否有可能通过只有一个提交(只有一个事务)做请求?

+0

将该行更改为“Session = sessionmaker(bind = engine,autocommit = True)”和。 在此行之后s = Session()添加“s.begin()”让我知道它是否有帮助? –

+0

不幸的是没有... – LovingFox

+0

我明白,这是MySQL中的一个约束(我想在SQLite中)。我需要的行为是“延迟约束检查”。 InnoDB的MySQL尚不支持它。 – LovingFox

回答

0

你能做到这样:

#u1=s.query(User).filter(User.name=="User1").first() 
#u2=s.query(User).filter(User.name=="User2").first() 

#u2.tech_id=None 
#u1.tech_id=10 
#s.commit() 

s.query(User).filter(User.name=="User2").update(
    {User.tech_id: None} 
) 
s.query(User).filter(User.name=="User1").update(
    {User.tech_id: 10} 
) 

s.commit() 

的改变的本质是执行的动作正确的顺序。即使在提交之前,您也无法为唯一键(至少在mysql中)创建重复值。但是您可以为唯一列创建多个NULL值。

+0

正如我在我的评论中所写的那样,由于InnoDB的限制,不可能为此任务执行一个事务。所以你写的解决方案是一样的:u2.tech_id = None; s.commit(); u1.tech_id = 10; s.commit() – LovingFox

+0

不。只有一个事务在我的例子中。模拟SQL:启动事务;更新1;更新2;承诺; –

+0

我试图再检查一次。有用。谢谢! – LovingFox