我有一个对象模型,它使用“动作”系统来跟踪对象的更改。可以添加这些操作并将其视为“建议”,直到它们通过“批准”操作获得批准。完整的操作列表被简化为“状态”对象,这些对象也存储在数据库中,以便更快地进行查询。
因为存在“建议”动作,所以每个对象还有一个跟踪“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()
我在这里做错了什么?