[英]Delete all in a Many to Many secondary table association in sqlalchemy
I have following models and associations: 我有以下模型和协会:
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')
When I am trying to delete a product I am getting following error: AssertionError 当我尝试删除产品时,我收到以下错误:AssertionError
AssertionError: Dependency rule tried to blank-out primary key column 'cart_products_association.cart_id' on instance '<CartProductsAssociation at 0x7f5fd41721d0>'
How can I solve it? 我该如何解决?
it solved the problem: 它解决了这个问题:
product = models.Product.query.get(product_id)
for ass in product.cart_associations:
db.session.delete(ass)
db.session.delete(product)
db.session.commit()
The error is caused by back references cart_associations and product_associations created by CartProductsAssociation
. 该错误是由CartProductsAssociation创建的后向引用cart_associations和product_associations
CartProductsAssociation
。 Since they don't have explicit cascades set, they have the default save-update, merge
, and without delete
the 由于它们没有明确的级联设置,因此它们具有默认的
save-update, merge
和不delete
default behavior is to instead de-associate ... by setting their foreign key reference to NULL.
默认行为是通过将其外键引用设置为NULL来取消关联。
Due to this when a Product
is up for deletion SQLAlchemy will first fetch the related CartProductsAssociation
objects and try to set the primary key to NULL. 因此,当
Product
被删除时,SQLAlchemy将首先获取相关的CartProductsAssociation
对象并尝试将主键设置为NULL。
It seems that originally there has been an attempt to use passive_deletes=True
with ondelete='CASCADE'
, but the passive deletes have ended up on the wrong side of the relationship pair. 似乎最初尝试使用
passive_deletes=True
和ondelete='CASCADE'
,但被动删除最终在关系对的错误一侧。 This should produce a warning: 这应该产生一个警告:
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.
If the relationships are configured as 如果关系配置为
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))
instead, then when a Product
instance that has not loaded its related CartProductsAssociation
objects is deleted, SQLAlchemy will let the DB handle cascading. 相反,当删除未加载其相关
CartProductsAssociation
对象的Product
实例时,SQLAlchemy将让DB处理级联。 Note that the SQLAlchemy delete
cascade is also necessary, or the error will come back if a Product
instance that has loaded its related association objects is deleted. 请注意,SQLAlchemy
delete
级联也是必需的,否则如果已删除已加载其相关关联对象的Product
实例,则会返回错误。 passive_deletes="all"
can also be used, if there are some special triggers or such in place in the DB that must be allowed to fire. 如果在DB中有一些必须允许触发的特殊触发器或类似触发器,也可以使用
passive_deletes="all"
。
When deleting a Product
that has loaded both carts and cart_associations the situation is even more complicated, because both association object pattern and a many to many relationship are in use, and the 2 relationships do not coordinate changes together – see the warning in "Association Object" . 当删除
Product
已加载两个推车和cart_associations的情况更复杂,因为两者的关联对象模式和多对多的关系都在使用,和2间的关系并不协调变更在一起-看到警告“关联对象“ 。 You might want to consider either making the other relationship viewonly , or use the association proxy extension across the association object relationship: 你可能要考虑做任何其他关系viewonly ,或使用协会代理跨越关联对象关系扩展:
class Product:
...
carts = association_proxy(
'cart_associations', 'cart',
creator=lambda cart: CartProductsAssociation(cart=cart))
Finally, the delete
cascade in Product.carts
is a bit odd, though may be as designed, and will delete the related Cart
objects along with the Product
if they have been loaded, and additionally removes rows from the secondary table. 最后,
Product.carts
的delete
级联有点奇怪,虽然可能是设计的,如果已经加载了将删除相关的Cart
对象以及Product
,并且还从辅助表中删除行。 On the other hand that relationship has passive deletes also, so the Cart
objects are not deleted if not loaded when the Product
is deleted, which would seem to conflict with the SQLAlchemy cascade. 另一方面,该关系也具有被动删除,因此如果在删除
Product
时未加载Cart
对象,则不会删除Cart
对象,这似乎与SQLAlchemy级联冲突。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.