2012-01-09 53 views
2

我有兩個表,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」...我不明白爲什麼。 在提交對象後嘗試修改對象時,我遇到過類似的問題;我應該錯過一些基本的東西,但是什麼?

+0

爲什麼你不使用最新版本,.7? – 2012-01-09 18:43:21

+0

,因爲最終使用它的機器運行的發行版只有0.5.8,我想避免手動安裝 – deubeuliou 2012-01-10 21:43:35

回答

2

你在這裏丟失的部分是堆棧跟蹤。總是看堆棧跟蹤 - 什麼是關鍵這裏是它的自動沖洗,通過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)

+0

禁用autoflush工作,非常感謝。以後我會記住解決方案B. – deubeuliou 2012-01-10 08:01:11

相關問題