【问题标题】:SQLAlchemy cascading deletes to many to many tableSQLAlchemy 级联删除到多对多表
【发布时间】:2021-02-05 12:08:53
【问题描述】:

我有一种情况,我想在删除键(父)时删除它的所有值(子),以及子和 Foo 之间的 MTM 关联中的相关行。 模型如下(部分属性去掉):


class Key(Model):
   ...
   values = relationship('Value', back_populates='key', cascade='all, delete-orphan')

class Value(Model):
   
   value = Column(Text, nullable=False)
   key = relationship("Key", back_populates="values")
   key_id = Column(Integer, ForeignKey("keys.id"))


class Foo(Model):

   ...
   taglist = db.relationship("Value", 
                               order_by="desc(Value.created)", 
                               secondary=association_table, 
                               lazy='dynamic')

association_table 只是一个经典的 FKFK 表:

Table("association_table", 
   Model.metadata,
   Column("foo.id", Integer, ForeignKey("foos.id"),
   Column("value.id", Integer, ForeignKey("values.id"),)

通过此设置,使用postgres,当我尝试删除密钥时,我得到以下信息: (psycopg2.errors.ForeignKeyViolation) update or delete on table "values" violates foreign key constraint "association_table_value_id_fkey" on table "association_table"

现在,阅读https://docs.sqlalchemy.org/en/14/orm/basic_relationships.html#relationships-many-to-many-deletion 文档,我已经尝试了那里的示例,这些示例似乎大多是在您的关联表上放置ondelete="CASCADE",但这会导致同样的问题。

有没有办法可以做我想做的事,例如从 MTM 表中“取消链接” foo 对象(不删除 它们)?

提前感谢您的帮助

【问题讨论】:

    标签: python postgresql flask sqlalchemy


    【解决方案1】:

    如果您使用postgres,了解您正在运行的版本会很有用。如果您使用的是低于 12.2 的版本,则有一些 similar issues 可能相关。

    但是,从您的代码中,您在哪里尝试ondelete="CASCADE"? 这对我有用:

    association = Table("association_table", 
       PkModel.metadata,
       Column("foo.id", ForeignKey("foos.id")),
       Column("value.id", ForeignKey("values.id", ondelete="CASCADE"))
       )
    
    
    class Key(PkModel):
        __tablename__ = "keys" 
        values = relationship('Value', back_populates='key', cascade='all, delete-orphan')
    
    
    class Value(PkModel):
        __tablename__ = "values"
        created = Column(DateTime, nullable=False, default=dt.utcnow)
        value = Column(Text, nullable=False)
        key = relationship("Key", back_populates="values")
        key_id = Column(ForeignKey("keys.id"))
    
    
    class Foo(PkModel):
        __tablename__ = "foos"
        taglist = relationship(
           "Value", 
            order_by="desc(Value.created)", 
            secondary=association, 
            lazy='dynamic'
    )
    
    

    然后我可以运行(使用postgres 12.2):

    >>>f1 = models.Foo.create()
    >>>f1.taglist.all()
    []
    >>>k1 = models.Key.create(values=[models.Value(value="bar")])
    >>>k1.values
    [<Value 54a7c726-acc9...b8c87e590>]
    >>>models.Value.query.all()
    [<Value 54a7c726-acc9...b8c87e590>]
    
    >>>f1.update(taglist=[v1])
    <Foo 8a1b6701-384e-4bc0-8e29-9ac4e64a4fdf>
    >>>f1 = models.Foo.query.all()[0]
    >>>f1.taglist.all()
    [<Value 54a7c726-acc9...b8c87e590>]
    
    >>>k1.delete()
    None
    >>>f1.taglist.all()
    []
    
    >>>models.Key.query.all()
    []
    >>>models.Value.query.all()
    []
    >>>models.Foo.query.all()
    [<Foo 8a1b6701-384e-4...4e64a4fdf>]
    

    我在没有ondelete="CASCADE" 的情况下尝试过,我可以重现你的错误。

    ForeignKeyViolation: update or delete on table "values" violates foreign key constraint "association_table_value.id_fkey" on table "association_table"
    

    从您的代码中,对于未来的读者,请注意以下几点:

    • 缺少__tablename__,我想您的代码中设置了添加's'。
    • 在关联表上,Column("foo.id") 上缺少)
    • 值没有名为“created”的映射列。

    【讨论】:

      猜你喜欢
      • 2011-03-15
      • 1970-01-01
      • 1970-01-01
      • 2013-01-13
      • 1970-01-01
      • 1970-01-01
      • 2012-01-29
      相关资源
      最近更新 更多