添加对象关联两个现有对象
我有两个表,testInstance和bugzilla的由第三个,bzCheck相关联,如下所示:添加对象关联两个现有对象
class Instance(Base):
__tablename__ = "testInstance"
id = Column(Integer, primary_key=True)
bz_checks = relation(BZCheck, backref="instance")
class BZCheck(Base):
__tablename__ = "bzCheck"
instance_id = Column(Integer, ForeignKey("testInstance.id"), primary_key=True)
bz_id = Column(Integer, ForeignKey("bugzilla.id"), primary_key=True)
status = Column(String, nullable=False)
bug = relation(Bugzilla, backref="checks")
class Bugzilla(Base):
__tablename__ = "bugzilla"
id = Column(Integer, primary_key=True)
后端是PostgreSQL服务器;我使用的SQLAlchemy 0.5
如果我创建实例,Bugzilla的和BZCheck ojects,然后做
bzcheck.bug = bugzilla
instance.bz_checks.append(bzcheck)
,然后添加并提交他们。一切安好。
但现在,让我们假设我有一个现有的实例和现有的Bugzilla,并希望他们交往:
instance = session.query(Instance).filter(Instance.id == 31).one()
bugzilla = session.query(Bugzilla).filter(Bugzilla.id == 19876).one()
check = BZCheck(status="OK")
check.bug = bugzilla
instance.bz_checks.append(check)
它失败:
In [6]: instance.bz_checks.append(check)
2012-01-09 18:43:50,713 INFO sqlalchemy.engine.base.Engine.0x...3bd0 select nextval('"bzCheck_instance_id_seq"')
2012-01-09 18:43:50,713 INFO sqlalchemy.engine.base.Engine.0x...3bd0 None
2012-01-09 18:43:50,713 INFO sqlalchemy.engine.base.Engine.0x...3bd0 ROLLBACK
它试图从获得一个新的ID未使用序列而不是使用外键“testInstance.id”...我不明白为什么。 在提交对象后尝试修改对象时,我遇到过类似的问题;我应该错过一些基本的东西,但是什么?
你在这里丢失的部分是堆栈跟踪。总是看堆栈跟踪 - 什么是关键这里是它的自动冲洗,通过instance.bz_checks
访问产生的:
Traceback (most recent call last):
File "test.py", line 44, in <module>
instance.bz_checks.append(check)
File "/Users/classic/dev/sqlalchemy/lib/sqlalchemy/orm/attributes.py", line 168, in __get__
return self.impl.get(instance_state(instance),dict_)
File "/Users/classic/dev/sqlalchemy/lib/sqlalchemy/orm/attributes.py", line 453, in get
value = self.callable_(state, passive)
File "/Users/classic/dev/sqlalchemy/lib/sqlalchemy/orm/strategies.py", line 563, in _load_for_state
result = q.all()
File "/Users/classic/dev/sqlalchemy/lib/sqlalchemy/orm/query.py", line 1983, in all
return list(self)
File "/Users/classic/dev/sqlalchemy/lib/sqlalchemy/orm/query.py", line 2092, in __iter__
self.session._autoflush()
File "/Users/classic/dev/sqlalchemy/lib/sqlalchemy/orm/session.py", line 973, in _autoflush
self.flush()
File "/Users/classic/dev/sqlalchemy/lib/sqlalchemy/orm/session.py", line 1547, in flush
self._flush(objects)
File "/Users/classic/dev/sqlalchemy/lib/sqlalchemy/orm/session.py", line 1616, in _flush
flush_context.execute()
File "/Users/classic/dev/sqlalchemy/lib/sqlalchemy/orm/unitofwork.py", line 328, in execute
rec.execute(self)
File "/Users/classic/dev/sqlalchemy/lib/sqlalchemy/orm/unitofwork.py", line 472, in execute
uow
File "/Users/classic/dev/sqlalchemy/lib/sqlalchemy/orm/mapper.py", line 2291, in _save_obj
execute(statement, params)
File "/Users/classic/dev/sqlalchemy/lib/sqlalchemy/engine/base.py", line 1405, in execute
params)
File "/Users/classic/dev/sqlalchemy/lib/sqlalchemy/engine/base.py", line 1538, in _execute_clauseelement
compiled_sql, distilled_params
File "/Users/classic/dev/sqlalchemy/lib/sqlalchemy/engine/base.py", line 1646, in _execute_context
context)
File "/Users/classic/dev/sqlalchemy/lib/sqlalchemy/engine/base.py", line 1639, in _execute_context
context)
File "/Users/classic/dev/sqlalchemy/lib/sqlalchemy/engine/default.py", line 330, in do_execute
cursor.execute(statement, parameters)
sqlalchemy.exc.IntegrityError: (IntegrityError) null value in column "instance_id" violates not-null constraint
'INSERT INTO "bzCheck" (bz_id, status) VALUES (%(bz_id)s, %(status)s) RETURNING "bzCheck".instance_id' {'status': 'OK', 'bz_id': 19876}
你可以看到这一点,因为这行代码是:
instance.bz_checks.append(check)
然后自动刷新:
self.session._autoflush()
File "/Users/classic/dev/sqlalchemy/lib/sqlalchemy/orm/session.py", line 973, in _autoflush
三种解决方案:
a。暂时禁用自动刷新功能(请参阅http://www.sqlalchemy.org/trac/wiki/UsageRecipes/DisableAutoflush)
b。确保总是与它创建的BZCheck关联对象的访问任何收集前需要满状态:
BZState(错误=的Bugzilla,实例=实例)
(这是通常用于关联的好主意对象 - 他们代表两点之间的关联,因此最适合用这个状态实例化)
c。更改级联规则,以便check.bug = somebug
的操作实际上不会将check
放置到刚才的会话中。您可以使用cascade_backrefs
来完成此操作,如http://www.sqlalchemy.org/docs/orm/session.html#controlling-cascade-on-backrefs所述。 (但你需要在0.6或0.7)
禁用autoflush工作,非常感谢。以后我会记住解决方案B. – deubeuliou 2012-01-10 08:01:11
为什么你不使用最新版本,.7? – 2012-01-09 18:43:21
,因为最终使用它的机器运行的发行版只有0.5.8,我想避免手动安装 – deubeuliou 2012-01-10 21:43:35