如何定义SQLAlchemy FK和关系以允许数据库级联删除



如何定义ForeignKey和关系,以便禁用SQLAlchemy的FK无效行为?这里的文档似乎描述了passive_deletes=True允许数据库级联删除,但仅在定义cascade关系的上下文中这里记录的财产,一个看起来对我来说,定义了SQLAlchemy将如何执行级联删除本身,被明确描述为比数据库引擎的速度慢本节中的级联删除(请参阅标题为ORM级别"delete"级联与FOREIGN KEY级别"ON delete"级联的绿框(。

要使用数据库的级联删除,我们应该执行以下操作吗?

  1. 在CCD_ 4列上定义CCD_
  2. 在相同关系上定义CCD_ 5
  3. AND 在对象之间的所有关系上定义cascade="delete, delete-orphan"参数

我似乎对第3步感到困惑:它似乎是在为SQLAlchemy定义级联,而不是允许数据库执行自己的删除。但是SQLAlchemy似乎希望在数据库获得级联删除的机会。我需要禁用此行为,但passive_deletes=True似乎不能单独执行。

这里的(迟来的(答案明确地解决了我的问题,但它不起作用。他表示

这里有一个重要的警告。注意到我是如何与passive_deletes=True指定关系的吗?如果你没有这些,整个事情就不会起作用。这是因为默认情况下,当您删除父记录时,SqlAlchemy会做一些非常奇怪的事情。它将所有子行的外键设置为NULL。因此,如果你从parent_table中删除一行,其中id = 5,那么它基本上会执行UPDATE child_table SET parent_id = NULL WHERE parent_id = 5

在我的代码中

class Annotation(SearchableMixin, db.Model):
id = db.Column(db.Integer, primary_key=True)
locked = db.Column(db.Boolean, index=True, default=False)
active = db.Column(db.Boolean, default=True)
HEAD = db.relationship("Edit",
primaryjoin="and_(Edit.current==True,"
"Edit.annotation_id==Annotation.id)", uselist=False,
lazy="joined", passive_deletes=True)
edits = db.relationship("Edit",
primaryjoin="and_(Edit.annotation_id==Annotation.id,"
"Edit.approved==True)", lazy="joined", passive_deletes=True)
history = db.relationship("Edit",
primaryjoin="and_(Edit.annotation_id==Annotation.id,"
"Edit.approved==True)", lazy="dynamic", passive_deletes=True)
all_edits = db.relationship("Edit",
primaryjoin="Edit.annotation_id==Annotation.id", lazy="dynamic",
passive_deletes=True)
class Edit(db.Model):
id = db.Column(db.Integer, primary_key=True)
edit_num = db.Column(db.Integer, default=0)
approved = db.Column(db.Boolean, default=False, index=True)
rejected = db.Column(db.Boolean, default=False, index=True)
annotation_id = db.Column(db.Integer,
db.ForeignKey("annotation.id", ondelete="CASCADE"), index=True)
hash_id = db.Column(db.String(40), index=True)
current = db.Column(db.Boolean, default=False, index=True, passive_deletes=True)
annotation = db.relationship("Annotation", foreign_keys=[annotation_id])
previous = db.relationship("Edit",
primaryjoin="and_(remote(Edit.annotation_id)==foreign(Edit.annotation_id),"
"remote(Edit.edit_num)==foreign(Edit.edit_num-1))")
priors = db.relationship("Edit",
primaryjoin="and_(remote(Edit.annotation_id)==foreign(Edit.annotation_id),"
"remote(Edit.edit_num)<=foreign(Edit.edit_num-1))",
uselist=True, passive_deletes=True)

简单地在父关系上设置passive_deletes=True是无效的。我还认为这可能是关系造成的从孩子到它的兄弟姐妹(关系Edit.previousEdit.priors(,但在这两个关系上设置passive_deletes=True不能解决问题吗?当我简单地运行Edit.query.get(n):时,它会导致以下警告

/home/malan/projects/icc/icc/venv/lib/python3.7/site packages/sqlalchemy/orm/reportions.py:1790:SA警告:在Edit.previous上,"passive_deletes"通常仅在一对多、一对一、多对多关系上配置。%自身(

/home/malan/projects/icc/icc/venv/lib/python3.7/site packages/sqlalchemy/orm/reportions.py:1790:SA警告:在Edit.priors上,"passive_deletes"通常仅在一对多、一对一、多对多关系上配置。%自身(

事实上,我在2015年发现了一个从未有过答案的有趣问题。它详细描述了一次执行文档代码的失败尝试。

似乎在彻底尝试分析我的关系后,我发现了问题。

首先,我将注意到,passive_deletes=True唯一的必需参数。您根本不需要定义cascade来利用数据库的级联系统。

更重要的是,我的问题似乎源于我的外国关键职位。我有一个级联,看起来像这样:

Annotation
/     |     
Vote    Edit   annotation_followers
/   
EditVote   tags

其中,为每个子类上的每个parent_id列定义了ondelete="CASCADE"。直到我在图中所有的子项上设置passive_deletes,无效行为仍然表现不佳。

对于遇到类似问题的人,我的建议是:彻底分析所有交叉关系,并在所有交叉关系上定义passive_deletes=True,这是有意义的。

也就是说,我仍在解决一些复杂问题;例如,在一个多对多表中,id甚至没有被取消。可能的下一个问题。

最新更新