class Basket:
name = models.CharField(max_length=50, blank=True, null=True)
class Apple:
name = models.CharField(max_length=50, blank=True, null=True)
basket = models.ForeignKey(Basket, on_delete=models.PROTECT)
...
myapple = new Apple(name="my")
myapple.save()
...
auto_created_basket = myapple.basket
myapple.basket = existing_basket
auto_created_basket.delete()
我尝试将auto_created_basket换成另一个,但是当我尝试删除它时出错。
"Cannot delete some instances of model 'Basket' because they are referenced through a protected foreign key: 'Apple.basket'", [<Apple: My apple>])
答案 0 :(得分:2)
在basket
模型中,basket = models.ForeignKey(Basket, on_delete=models.PROTECT)
字段是外键
on_delete
其on_delete
属性明确指出,当他们所在的篮子被删除时,不应删除苹果。
正如official docs所说
删除ForeignKey引用的对象时,Django by default模拟SQL约束ON DELETE CASCADE的行为 并删除包含ForeignKey的对象。
和
PROTECT参数可防止通过引发删除引用的对象 ProtectedError
因此,最简单的步骤应该是删除basket = models.ForeignKey(Basket)
参数并使用默认行为
{{1}}
但是,请查看ForeignKey model field的所有可能参数,并选择适合您的应用/方案要求的组合。
答案 1 :(得分:1)
您可以尝试将苹果从auto_created_basket
移至existing_basket
,然后再删除购物篮:
>>> auto_created_basket.apple_set.update(basket=existing_basket)
>>> auto_created_basket.delete()
或
>>> myapple.basket = existing_basket
>>> myapple.save()
>>> auto_created_basket.delete()
或者,如果您想在一个购物篮中收集来自已删除购物篮的苹果,您可以将功能分配给on_delete
属性,如下所示:
def get_sentinel_basket():
basket, created = Basket.objects.get_or_create(name='DELETED')
return basket
-
basket = models.ForeignKey(Basket, on_delete=models.SET(get_sentinel_basket))
因此,当删除购物篮时,该购物篮中苹果的.basket
属性将自动设置为Basket(name='DELETED')
。
答案 2 :(得分:1)
我讨厌回答我的问题,但我的例子太简单了。答案非常好。
在真实产品中,涉及post_save
信号,负责创建auto_created_basket
。
问题在于,当我说myapple.basket = existing_basket
Django的图层很好,但DB仍然保留对较旧关系的引用。我的解决方案是在我再次保存auto_created_basket.delete()
后移动myapple
。