在SqlAlchemy中将子类添加到会话时出现外键冲突

时间:2018-02-09 14:26:38

标签: python postgresql sqlalchemy

我有目前的情况:

Base = declarative_base()

class Parent(Base):
    __tablename__ = 'parent'

    id = Column(String(32), primary_key=True, index=True)


class Child(Parent):
    __tablename__ = 'child'

    parent_id = Column(ForeignKey('parent.id'), primary_key=True)
    other_field = Column(String(32))


class Other(Base):
    __tablename__ = 'other'

    id = Column(String(32), primary_key=True, index=True)
    reference_to_parent = Column(ForeignKey('parent.id'), primary_key=True)


child = Child(id='some_id', other_field="blah")
session.add(child)

other = Other(id="some_other_id", reference_to_parent='some_id')
session.add(other)
session.commit()  # <-- sqlalchemy.exc.IntegrityError

在提交时,我收到错误:

sqlalchemy.exc.IntegrityError: (psycopg2.IntegrityError) insert or update on table "other" violates foreign key constraint
DETAIL:  Key (reference_to_parent)=(some_id) is not present in table "parent".

但是,如果我这样做:

child = Child(id='id', other_field="blah")
session.add(child)
session.commit() . # <-- note the extra commit

other = Other(reference_to_parent='id')
session.add(other)
session.commit()

我没有得到这样的错误。似乎SQLAlchemy没有认识到我添加到会话中的孩子实际上是Parent的一个实例,并且会在该表中创建一行。

知道我做错了什么吗?它并不觉得应该需要提交。

1 个答案:

答案 0 :(得分:1)

我认为您需要在首次添加后添加session.flush()。 Flush基本上会将您的更改传递给处于挂起状态的数据库。 Commit实际上会将它们写入数据库。

child = Child(id='some_id', other_field="blah")
session.add(child)
session.flush()

other = Other(id="some_other_id", reference_to_parent='some_id')
session.add(other)
session.commit()