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

时间:2017-07-04 09:43:12

标签: python flask sqlalchemy 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')

当我尝试删除某个产品时,我收到以下错误消息: 的AssertionError

AssertionError: Dependency rule tried to blank-out primary key column 'cart_products_association.cart_id' on instance '<CartProductsAssociation at 0x7f5fd41721d0>'

我该如何解决?

2 个答案:

答案 0 :(得分:2)

它解决了这个问题:

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

 for ass in product.cart_associations:

    db.session.delete(ass)

db.session.delete(product)
db.session.commit()

答案 1 :(得分:1)

该错误是由CartProductsAssociation创建的后向引用 cart_associations product_associations 引起的。由于它们没有明确的cascades设置,因此它们具有默认save-update, merge,而没有delete

  

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

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

似乎最初尝试将passive_deletes=Trueondelete='CASCADE'一起使用,但被动删除最终导致了关系对的错误一面。这应该产生警告:

  

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.

如果关系配置为

class CartProductsAssociation(db.Model):
    ...
    product = db.relationship(
        "Product", backref=db.backref("cart_associations",
                                      cascade="all",
                                      passive_deletes=True))
    cart = db.relationship(
        "Cart", backref=db.backref("product_associations",
                                   cascade="all",
                                   passive_deletes=True))

相反,当没有加载其相关Product对象的CartProductsAssociation实例被删除时,SQLAlchemy将让DB处理级联。请注意,SQLAlchemy delete级联也是必需的,否则如果加载其相关关联对象的Product实例被删除,则会返回错误。如果在DB中有一些必须允许触发的特殊触发器或类似触发器,也可以使用passive_deletes="all"

删除已加载购物车 cart_associations Product时,情况会更复杂,因为association object模式和{ {3}}关系正在使用中,并且两个关系不会一起协调更改 - 请参阅many to many中的警告。您可能想要考虑建立其他关系"Association Object",或者在关联对象关系中使用viewonly扩展名:

class Product:
    ...
    carts = association_proxy(
        'cart_associations', 'cart',
        creator=lambda cart: CartProductsAssociation(cart=cart))

最后,delete中的Product.carts级联有点奇怪,但可能与设计完全相同,并会删除相关的Cart个对象以及Product已加载,并另外从辅助表中删除行。另一方面,该关系也具有被动删除功能,因此如果在删除Cart时未加载Product对象,则

}级联。