在我的应用程序中,Parent实例与Child实例具有一对多关系。每个父母可能有很多孩子,但每个孩子可能只有一个父母。我了解这种关系是如何工作的。
一个重要的功能是在任何时候,只有一位父母的孩子可以活动。最初,我试图通过在Child模型上使用布尔值来表示这一点,但是强制实施约束太困难了。相反,我选择使用关联表,该表只记录给定时间哪些孩子处于活动状态。
这是dbdiagram.io生成的diagram of the relationship。
为了表示这种关系,我使用uselist=True
标志,该标志告诉SQLAlchemy在通过关系查询时返回单个实例而不是列表。
我需要能够删除这些关系,从而停用子级,而不删除父级或子级。我尝试使用session.delete(parent.active_child)
,但这会删除Child记录,而不仅仅是关联。我看到有special instructions for deleting from M2M relationships,但是这假定关系查询返回一个列表,从而使开发人员可以使用association.remove(instance)
。就我而言,这是不正确的。
请参见以下示例。注意父模型上的两个关系。
children_active = Table('children_active', Base.metadata,
Column('parent_id', Integer, ForeignKey('parents.id'), primary_key=True, unique=True),
Column('child_id', Integer, ForeignKey('children.id'), primary_key=True)
)
class Parent(Base):
__tablename__ = 'parents'
id = Column(Integer, primary_key=True)
children = relationship("Child", backref='parent')
active_child = relationship("Child", secondary=children_active, uselist=False)
class Child(Base):
__tablename__ = 'children'
id = Column(Integer, primary_key=True)
parent_id = Column(Integer, ForeignKey('parents.id'))
p1 = Parent()
p1.children = [Child() for i in range(3)]
p1.active_child = p1.children[0]
print(p1.children) # [Child<1>, Child<2>, Child<3>]
print(p1.active_child) # Child<1>
session.delete(p1.active_child)
print(p1.children) # [Child<2>, Child<3>]
print(p1.active_child) # None
active_child
为空,这是正确的,但是它代表的Child对象也被删除,这是不可接受的。
答案 0 :(得分:1)
我知道了。重新分配active_child
值将覆盖该关系,并使Child
对象保持不变。将active_child
设置为None
会删除关系。
p1 = Parent()
p1.children = [Child() for i in range(3)]
p1.active_child = p1.children[0]
print(p1.children) # [Child<1>, Child<2>, Child<3>]
print(p1.active_child) # Child<1>
p1.active_child = p1.children[1]
session.commit()
print(p1.children) # [Child<1>, Child<2>, Child<3>]
print(p1.active_child) # Child<2>
p1.active_child = None
session.commit()
print(p1.children) # [Child<1>, Child<2>, Child<3>]
print(p1.active_child) # None