删除具有多对多关系的行

Posted

技术标签:

【中文标题】删除具有多对多关系的行【英文标题】:Deleting a row with a many-to-many relationship 【发布时间】:2012-06-12 21:20:04 【问题描述】:

我有两张桌子,imagerestaurant。我已经在它们之间建立了多对多的关系。

以下是表定义的相关部分:

images_assoc = Table('restaurant_image_assoc', Base.metadata,
        Column('restaurant', Integer(unsigned=True),
            ForeignKey('restaurant.id')),
        Column('image', Integer(unsigned=True),
            ForeignKey('image.id')))

class Image(Base):
    __tablename__ = 'image'
    id = Column(Integer(unsigned=True), primary_key=True)
    reports = Column(TinyInt, nullable=False, default=0)
    created_at = Column(DateTime, default=datetime.now)

class Restaurant(Base):
    __tablename__ = 'restaurant'
    id = Column(Integer(unsigned=True), primary_key=True)
    images = relationship(Image, secondary=images_assoc)

我需要删除image 中的一行,但当然我需要删除restaurant_image_assoc 中首先指向它的所有行。我该怎么做?

我试过这个:

request.db.query(images_assoc)\
        .filter(images_assoc.c.image==image.id).delete()
request.db.delete(image)
request.db.commit()

image 是我要删除的行,但出现此错误:

AttributeError: 'Table' object has no attribute 'class_'

【问题讨论】:

你试过在image和image_assoc的关系上设置delete-orphan cascade吗? see here 没有关系,当我尝试做一个时,它开始对我大喊大叫。我目前已经使用原始 SQL 破解了一些东西。 >. 这里的具体错误消息是 Query() 现在不能与这样的表一起使用 (query(images_assoc)...delete())。不过,与其他答案一样,只需操作 Restaurant.images 就会自动处理 images_assoc 中的行 - 因为它是“次要的”,所以与级联设置无关。也就是说,如果你说restaurant.images.remove(some_image),然后flush,这就是你需要删除images_assoc中的行。 问题是当你有太多的对象。 SqlAlchemy 会引发大量删除操作。在我们的例子中,每个对象最多有 55000k 行,我们有大约 2k 个对象。我们的 postgres 速度很快,但运行 55k*2k = 1.1 亿次查询需要很长时间 【参考方案1】:

如果您删除图像中的一行,您应该获得该图像 ID。然后你可以在你的 assoc 表中删除 image id == your image id。

【讨论】:

我什至做不到。我更新了我的帖子以展示我的尝试。【参考方案2】:

问题在于 SA 没有从 Image 的一侧跟踪 Restaurant 和 Image 之间的关系,因此它“不知道”存在依赖关系。一旦你从对方配置了关系,关联表中的相应行也将被自动删除。为了添加关系的另一端,只需使用backref

class Restaurant(Base):
    images = relationship(Image, secondary=images_assoc, backref="restaurants")

但您也可以在每个对象上显式定义它们(在这种情况下需要back_populates):

class Image(Base):
    restaurants = relationship("Restaurant", secondary=images_assoc, back_populates="images")
class Restaurant(Base):
    images = relationship(Image, secondary=images_assoc, back_populates="restaurants")

但后者在语义上与使用backref 相同。

【讨论】:

以上是关于删除具有多对多关系的行的主要内容,如果未能解决你的问题,请参考以下文章

具有多对多关系的级联删除[重复]

从具有多对多关系核心数据iOS的上下文中删除nsmanagedboject

Symfony2 删除并保存多对多关系

具有额外多对多关系的 JPA 多对多

在多对多关系中删除正确

多对多manytomany