SQLalchemy:post_update = True

时间:2018-05-15 17:21:32

标签: python sqlalchemy

我有一个对象模型,它使用“动作”系统来跟踪对象的更改。可以添加这些操作并将其视为“建议”,直到它们通过“批准”操作获得批准。完整的操作列表被简化为“状态”对象,这些对象也存储在数据库中,以便更快地进行查询。

因为存在“建议”动作,所以每个对象还有一个跟踪“diff”的第二个状态对象,它们基本上是建议中所有内容的状态变化(所有其他字段设置为NULL)。最后,每个州还跟踪最后一个动作,以便在UI中显示“上次更新”。

这是我的目标:

class Subject(Base):
    __tablename__ = 'subjects'

    id = Column(UUID(as_uuid=True), primary_key=True)
    state_id = Column(UUID(as_uuid=True), ForeignKey('states.id', name="fk_state"))
    diff_id = Column(UUID(as_uuid=True), ForeignKey('states.id', name="fk_state_diff"))

    state = relationship('State', back_populates='subject', foreign_keys=[state_id], cascade='all, delete-orphan', lazy='joined', innerjoin=True, uselist=False, single_parent=True, post_update=True)
    diff = relationship('State', back_populates='subject', foreign_keys=[diff_id], cascade='all, delete-orphan', lazy='joined', innerjoin=True, uselist=False, single_parent=True, post_update=True)
    actions = relationship('Action', back_populates='subject', cascade='all, delete-orphan', order_by='Action.time', single_parent=True)

如您所见,它与此Action对象有关系:

class Action(Base):
    __tablename__ = 'actions'

    id = Column(UUID(as_uuid=True), primary_key=True)
    subject_id = Column(UUID(as_uuid=True), ForeignKey('subjects.id'), nullable=False, index=True)

    time = Column(DateTime(timezone=True), server_default=func.now(), nullable=False, index=True)
    # Other action properties here, omitted for brevity.
    # ...

    subject = relationship('Subject', back_populates='actions')

这两个都与State对象有关,它提出了(多对多)和last_action属性。

proposed_action_data = Table(
    'proposed_actions',
    Base.metadata,
    Column('actions_id', UUID(as_uuid=True), ForeignKey('actions.id')),
    Column('state_id', UUID(as_uuid=True), ForeignKey('states.id'))
)

class State(Base):
    __tablename__ = 'states'

    id = Column(UUID(as_uuid=True), primary_key=True)
    last_action_id = Column(UUID(as_uuid=True), ForeignKey('actions.id', name="fk_state_last_action"), nullable=True)
    subject_id = Column(UUID(as_uuid=True), ForeignKey('subjects.id', name="fk_state_subject_id"), nullable=False)

    # State properties goes here, ommitted for brevity.
    # ...

    last_action = relationship('Action', lazy='joined', foreign_keys=[last_action_id], post_update=True)
    proposed = relationship('Action', secondary=proposed_action_data)
    subject = relationship('Subject', foreign_keys=[subject_id)

插入似乎工作正常 - 我可以设置状态和差异,并在状态UPDATE语句后为Subject发出INSERT语句,因此ID已设置。

但是如果我想删除一个Subject,则删除前UPDATE语句以清除state_id并且diff_id不会运行,因此它会尝试删除State并失败,因为它仍然被引用:

session.delete(subject)
session.commit()

提出:

sqlalchemy.exc.IntegrityError: (psycopg2.IntegrityError) update or delete on table "states" violates foreign key constraint "fk_state_diff" on table "subjects"
DETAIL:  Key (id)=(363eb5bb-4042-44a9-b3fe-567406008f9e) is still referenced from table "subjects".
[SQL: 'DELETE FROM states WHERE states.id = %(id)s'] [parameters: ({'id': UUID('363eb5bb-4042-44a9-b3fe-567406008f9e')}, {'id': UUID('b7ca4f02-0fac-41bf-ae8b-44049ceb1855')})]

如果我手动清除状态和差异,我没有例外:

subject.state = None
subject.diff = None
session.delete(subject)
session.commit()

我在这里做错了什么?

0 个答案:

没有答案