SQLAlchemy在更改其子项中对它的所有引用后删除父项仍然会删除子项

时间:2017-01-09 22:34:23

标签: python sqlalchemy

鉴于此SQLAlchemy数据库定义:

class Project(Base):
    __tablename__ = 'project'
    id = Column(Integer, primary_key=True)
    name = Column(Unicode, unique=True)
    tasks = relationship('Task', cascade='all', backref='project')

class Task(Base):
    __tablename__ = 'task'
    id = Column(Integer, primary_key=True)
    title = Column(Unicode)
    project_id = Column(Integer, ForeignKey('project.id'), nullable=False)

我想合并两个项目。我的第一个天真的尝试是做这样的事情:

def merge_1(session, src_prj, dst_prj):
    for task in src_prj.tasks:
        task.project = dst_prj
    session.delete(src_prj)

但这导致只有一半(!)的任务被转移,另一半被删除。

如果我这样做:

def merge_2(session, src_prj, dst_prj):
    for task in src_prj.tasks:
        task.project_id = dst_prj.id
    session.delete(src_prj)

我的任务都没有转移。删除项目时会删除它们。

然后我试了一下:

def merge_3(session, src_prj, dst_prj):
    for task in src_prj.tasks:
        task.project_id = dst_prj.id
    session.commit()
    session.delete(src_prj)

它有效,但在删除项目之前调用session.commit()会破坏会话事务的目的。

这个最终版本也可以(并且速度更快):

def merge_4(session, src_prj, dst_prj):
    session.query(Task).filter_by(project_id=src_prj.id) \
            .update({'project_id': dst_prj.id})
    session.delete(src_prj)

但我想知道为什么merge_1()merge_2()的行为不符合预期。

我使用SQLAlchemy 1.1.4进行了测试。完整的测试程序可在此处获取:https://gist.github.com/agateau/887af14b7ddd1e151f9ac89d5e423ef6

1 个答案:

答案 0 :(得分:0)

我会尝试在执行删除操作之前提交更改。否则,我猜测删除没有直接识别它之前的提交操作:

def merge_1(session, src_prj, dst_prj):
    for task in src_prj.tasks:
        task.project = dst_prj
    session.commit()
    session.delete(src_prj)

您可以在更新声明中而不是单独执行此操作吗?类似的东西:

Project.objects.filter(name=src_prj).update(name=dst_prj)
Project.objects.filter(name=src_prj).delete()