SQLAlchemy:如何直接从一对多的关系中删除对象,而不使用session.delete()方法?

23

我有以下的SQLAlchemy设置:

Base = declarative_base()

class Post(Base):
    __tablename__ = 'post'
    id = Column(Integer, primary_key=True)
    title = Column(String(30))
    comments = relationship('Comment', cascade='all')

class Comment(Base):
    __tablename__ = 'comment'
    id = Column(Integer, primary_key=True)
    post_id = Column(Integer, ForeignKey(Post.id, ondelete='CASCADE'), nullable=False)
    text = Column(Text)

通过这个方式,我可以创建一个帖子对象,并与评论形成一对多的关系。我想处理与会话无关的帖子评论的创建和删除。将评论添加到帖子中完全没有问题:

post = Post(title='some post')
comment = Comment(text='some comment')
post.comments.append(comment)

我的会话处理程序只知道帖子,所以它会执行 session.add(post),评论会自动放入会话中,并在下一个 session.commit() 中与数据库同步。不过,删除评论就不是这样了。我想通过以下方式能够删除评论:

post.comments.remove(comment)

然而,在下一个 session.commit() 中会出现以下错误:

sqlalchemy.exc.OperationalError: (OperationalError) (1048, "Column 'post_id' cannot be null") 'UPDATE comment SET post_id=%s WHERE comment.id = %s' (None, 1L)
如何告诉SQLAlchemy,在post_id列上由于非空约束而不允许使用NULL值的情况下,不要更新评论,而是删除评论?我知道我可以使用session.delete(comment),但由于我没有显式地向会话添加评论,因此我认为我不需要显式地从会话中删除它。我找到了几个解决相关对象级联删除的解决方案,但由于我从未向会话发出任何显式删除请求(帖子仍然存在),所以我认为这种方法不适用。
编辑:我调整了示例,以包括从帖子进行级联删除。现在可以通过session.delete(post)实现并删除所有评论。但我只想自动删除我从关系中移除的评论,而不是删除带有所有评论的整个帖子。
TL;DR:如何告诉SQLAlchemy在一对多关系的关系列表中删除一个条目时发出删除语句而不是更新语句?
2个回答

32

阅读文档中的配置删除/删除孤儿级联部分以获取更多信息,但基本上您需要在relationshipcascade选项中添加delete-orphan:

class Post(Base):
    # ...
    comments = relationship('Comment', cascade="all, delete-orphan")

通过级联中的 delete-orphan 选项,从关系列表中删除时的删除操作按预期工作。谢谢。 - Varicus

2

我不是SQLAlchemy的用户,但我认为你应该使用ondelete选项

    post_id = Column(Integer, ForeignKey(Post.id, ondelete="CASCADE"), nullable=False)

可以参考Mysql 5.6手册 13.6.44,外键约束

SET NULL:从父表中删除或更新行,并将子表中的外键列设置为NULL。同时支持ON DELETE SET NULL和ON UPDATE SET NULL子句。
CASCADE:从父表中删除或更新行,并自动删除或更新匹配的子表中的行。同时支持ON DELETE CASCADE和ON UPDATE CASCADE。在两个表之间,不要定义几个在父表或子表中对同一列起作用的ON UPDATE CASCADE子句。

具体可见 http://docs.sqlalchemy.org/en/rel_0_9/core/constraints.html -> Defining Foreign Keys -> ON UPDATE and ON DELETE


这可能适用于使用session.delete(post)删除帖子的情况,但我没有这样做。因此,没有任何级联到评论。我只想删除评论。 - Varicus

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接