如何删除uselist = True

时间:2019-07-29 17:24:37

标签: sqlalchemy flask-sqlalchemy

在我的应用程序中,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对象也被删除,这是不可接受的。

1 个答案:

答案 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