如何定义一个ForeignKey和关系,以便可以禁用SQLAlchemy的FK无效行为?
here文档似乎描述了
passive_deletes=True
允许数据库级联删除,但仅在定义cascade
关系的上下文中
属性documented here,似乎是一个属性
对我来说,定义了SQLAlchemy如何自行执行级联删除,被明确描述为比数据库引擎的慢
级联删除 in this section
(请参见标题为 ORM级“删除”级联与“外键”级“ ON DELETE”级联的绿色框。)
要使用数据库的级联删除,我们应该执行以下操作吗?
ondelete="CASCADE"
列上定义ForeignKey
,passive_deletes=True
,cascade="delete, delete-orphan"
参数?这是我似乎很困惑的第3步:它似乎是在为SQLAlchemy定义级联,而不是允许数据库
执行它自己的删除。但是SQLAlchemy似乎想在数据库可以获取 之前清空所有依赖的外键。
有机会进行级联删除。我需要禁用此行为,但是passive_deletes=True
似乎不是自己完成的。
(最新)答案here明确解决了我的问题,但是没有用。他说
这里有一个重要的警告。注意我如何与
passive_deletes=True
指定关系?如果您没有该功能,则整个操作将无法进行。 这是因为默认情况下,当您删除父记录时,SqlAlchemy所做的事情确实很奇怪。 它将所有子行的外键设置为NULL
。因此,如果您从parent_table
的{{1}}处删除一行,那么它将基本上执行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.previous
),但在这两个关系上设置Edit.priors
不能解决问题,当我只运行passive_deletes=True
时,它会导致以下警告:
/home/malan/projects/icc/icc/venv/lib/python3.7/site-packages/sqlalchemy/orm/relationships.py:1790:SA警告:在Edit.previous上,“ passive_deletes”通常配置为一对多,一对一,多对多关系。 %self)
/home/malan/projects/icc/icc/venv/lib/python3.7/site-packages/sqlalchemy/orm/relationships.py:1790:SAWarning:在Edit.priors上,“ passive_deletes”通常配置为一对多,一对一,多对多关系。 %self)
我实际上发现了2015年的this有趣的问题,但从未得到答案。详细介绍了执行文档代码失败的尝试。
答案 0 :(得分:0)
似乎在尝试分析我的人际关系后,我发现了问题所在。
首先,我要注意,passive_deletes=True
是仅 必需的参数。您根本不需要定义cascade
来利用数据库的级联系统。
更重要的是,我的问题似乎源于我的外键依赖树。我有一个看起来像这样的小瀑布:
Annotation
/ | \
Vote Edit annotation_followers
/ \
EditVote tags
在每个子类的每个ondelete="CASCADE"
列中定义了parent_id
的位置。直到我在图中的 all 个子级上设置了active_deletes为止,无效行为仍然不正常。
对于遇到类似问题的任何人,我的建议是:彻底分析您所有相交的关系,并在所有有意义的条件下定义passive_deletes=True
。
那是说,我还在解决一些并发症;例如,在多对多表中,id甚至没有失效。可能的下一个问题。