删除sqlalchemy中多对多辅助表关联中的所有内容

sad*_*605 5 python sqlalchemy flask flask-sqlalchemy

我有以下模型和关联:

class CartProductsAssociation(db.Model):
    __tablename__ = 'cart_products_association'
    cart_id = db.Column(db.Integer, db.ForeignKey('carts.id',ondelete='CASCADE'),primary_key=True)
    product_id = db.Column(db.Integer, db.ForeignKey('products.id',ondelete='CASCADE'), primary_key=True)
    quantity = db.Column(db.Integer)

    product = db.relationship("Product", backref="cart_associations", cascade="all,delete",passive_deletes=True)
    cart = db.relationship("Cart", backref="product_associations",cascade="all,delete",passive_deletes=True)


class Product(db.Model):
    __tablename__ = 'products'
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String)
    img_path = db.Column(db.String)

    price = db.Column(db.Float, default=0.0)

    product_categories = db.relationship(
        "ProductCategory",
        secondary=product_product_categories,
        back_populates="products")

    carts = db.relationship("Product", secondary="cart_products_association",passive_deletes=True,cascade="all,delete" )

class Cart(db.Model):
    __tablename__ = 'carts'
    id = db.Column(db.Integer, primary_key=True)

    branch_id = db.Column(db.Integer, db.ForeignKey('branch.id'))
    branch = db.relationship("Branch", back_populates="carts")

    page_id = db.Column(db.Integer, db.ForeignKey('pages.id'))
    page = db.relationship("Page", back_populates="carts")


    shopper_id = db.Column(db.String, db.ForeignKey('shoppers.fb_user_id'))
    shopper = db.relationship(
        "Shopper",
        back_populates="carts")

    products = db.relationship("Product", secondary="cart_products_association")
    cart_status = db.Column(db.Enum('user_unconfirmed','user_confirmed','client_unconfirmed','client_confirmed', name='cart_status'), default='user_unconfirmed')
Run Code Online (Sandbox Code Playgroud)

当我尝试删除产品时出现以下错误:AssertionError

AssertionError: Dependency rule tried to blank-out primary key column 'cart_products_association.cart_id' on instance '<CartProductsAssociation at 0x7f5fd41721d0>'
Run Code Online (Sandbox Code Playgroud)

我该如何解决?

sad*_*605 5

它解决了问题:

 product = models.Product.query.get(product_id)

 for ass in product.cart_associations:

    db.session.delete(ass)

db.session.delete(product)
db.session.commit()
Run Code Online (Sandbox Code Playgroud)


Ilj*_*ilä 5

该错误是由创建的反向引用cart_associationsProduct_associationsCartProductsAssociation引起的。由于它们没有设置显式级联,因此它们具有默认值,save-update, merge并且没有delete

\n\n
\n

默认行为是通过将外键引用设置为 NULL 来取消关联...。

\n
\n\n

因此,当Product要删除 a 时,SQLAlchemy 将首先获取相关CartProductsAssociation对象并尝试将主键设置为 NULL。

\n\n

看来最初曾尝试使用passive_deletes=Truewith ondelete=\'CASCADE\',但被动删除最终出现在关系对的错误一侧。这应该会产生一个警告:

\n\n
\n

sqlalchemy/orm/relationships.py:1790: SAWarning: On CartProductsAssociation.product, \'passive_deletes\' is normally configured on one-to-many, one-to-one, many-to-many relationships only.

\n
\n\n

如果关系配置为

\n\n
class CartProductsAssociation(db.Model):\n    ...\n    product = db.relationship(\n        "Product", backref=db.backref("cart_associations",\n                                      cascade="all",\n                                      passive_deletes=True))\n    cart = db.relationship(\n        "Cart", backref=db.backref("product_associations",\n                                   cascade="all",\n                                   passive_deletes=True))\n
Run Code Online (Sandbox Code Playgroud)\n\n

相反,当删除加载其相关对象的Product实例时,SQLAlchemy 将让 DB 处理级联。注意,SQLAlchemy级联也是必要的,否则如果删除加载了相关关联对象的实例,则会返回错误。如果数据库中存在一些特殊触发器或必须允许触发的此类触发器,也可以使用。CartProductsAssociationdeleteProductpassive_deletes="all"

\n\n

Product当删除同时加载了cartscart_associations的 a 时,情况会更加复杂,因为关联对象模式和多对多关系都在使用中,并且这 2 个关系不会一起协调更改 \xe2\x80\x93 请参阅警告在“关联对象”中。您可能需要考虑将其他关系设置为viewonly ,或者在关联对象关系中使用关联代理扩展:

\n\n
class Product:\n    ...\n    carts = association_proxy(\n        \'cart_associations\', \'cart\',\n        creator=lambda cart: CartProductsAssociation(cart=cart))\n
Run Code Online (Sandbox Code Playgroud)\n\n

最后,delete级联Product.carts有点奇怪,尽管可能是按照设计的,并且将删除相关Cart对象以及Product它们是否已加载,并且另外从辅助表中删除行。另一方面,该关系也具有被动删除,因此如果在删除时未加载Cart对象,则不会Product删除对象,这似乎与 SQLAlchemy 级联冲突。

\n