Django中使用related_name时on_delete=models.CASCADE不生效问题
解决Django中多外键关联时的级联删除问题
首先,咱们先揪出你测试用例里的关键问题——这大概率是你觉得on_delete=models.CASCADE没生效的根源:
你给created_proposal.created_by_customer赋值了buyer,但没有调用created_proposal.save(),数据库里的Proposal记录根本没和这个Customer建立关联。这时候删除buyer,自然不会触发级联删除操作。
修正后的测试用例
@pytest.mark.django_db def test_delete_proposal_from_created_by_customer(): """ Deleting customer that created the proposal must delete proposal """ created_proposal = random_proposal() buyer = random_customer() created_proposal.created_by_customer = buyer created_proposal.save() # 核心步骤:保存修改后的关联关系到数据库 buyer.delete() # 现在删除Customer,Proposal会被级联删除 # 验证Proposal确实被删除 assert Proposal.objects.filter(id=created_proposal.id).exists() is False
关于on_delete=models.CASCADE的实际作用
你的模型定义其实已经完美满足需求了:
- 当
created_by_customer关联的Customer被删除时,对应的Proposal会自动被删除 - 当
accepted_by_customer关联的Customer被删除时,对应的Proposal同样会自动被删除
这是Django外键on_delete=models.CASCADE的原生行为——只要外键指向的对象被删除,拥有该外键的对象就会被级联删除。所以只要测试逻辑正确(保存关联关系),这个设置完全能实现你要的效果。
Django 4.0中的进阶方案(仅适用于复杂场景)
如果你的需求比“任意一个关联Customer删除则删除Proposal”更复杂(比如需要满足额外条件才触发删除),可以使用Django的信号系统,但一般不推荐用它替代默认的on_delete设置——信号会让逻辑变得隐蔽,不如直接的外键约束直观易懂。
举个信号实现的示例(仅作演示,你的场景其实不需要):
from django.db.models.signals import pre_delete from django.dispatch import receiver from .models import Customer, Proposal @receiver(pre_delete, sender=Customer) def delete_proposals_on_customer_delete(sender, instance, **kwargs): # 删除所有关联到当前Customer的Proposal Proposal.objects.filter(created_by_customer=instance).delete() Proposal.objects.filter(accepted_by_customer=instance).delete()
最后总结:先修正测试里的保存步骤,on_delete=models.CASCADE完全能满足你的需求,这也是Django官方推荐的最佳实践,不需要额外的信号处理。
内容的提问来源于stack exchange,提问作者Jose Machado
相关产品推荐
相关产品推荐

