删除在 PROTECTED ForeignKey 下自动创建的模型
Deleting auto created model which is under PROTECTED ForeignKey
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>])
在您的 Apple
模型中,basket
字段是一个外键
basket = models.ForeignKey(Basket, on_delete=models.PROTECT)
其 on_delete
属性值明确声明通过防止删除篮子来保护苹果。
正如official docs所说
When an object referenced by a ForeignKey is deleted, Django by
default emulates the behavior of the SQL constraint ON DELETE CASCADE
and also deletes the object containing the ForeignKey.
和
the PROTECT parameter prevents deletion of the referenced object by raising
ProtectedError
因此,最简单的步骤应该是删除 on_delete
参数并使用默认行为
basket = models.ForeignKey(Basket)
但是,请查看 ForeignKey model field 的所有可能参数,然后选择适合您的 application/scenario 要求的组合。
更新:
最新的 Django 版本需要 on_delete
。只是不要删除它并添加您想要的参数(如 on_delete=models.CASCADE
)。
您可以先尝试将苹果从 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')
。
我不想回答我的问题,但我的例子过于简单化了。回答的很到位。
在实际产品中涉及 post_save
个信号,例如负责创建 auto_created_basket
。
问题是当我说 myapple.basket = existing_basket
Django 的层没问题,但数据库仍然持有对旧关系的引用。我的解决方案是在我再次保存 myapple
后移动 auto_created_basket.delete()
。
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>])
在您的 Apple
模型中,basket
字段是一个外键
basket = models.ForeignKey(Basket, on_delete=models.PROTECT)
其 on_delete
属性值明确声明通过防止删除篮子来保护苹果。
正如official docs所说
When an object referenced by a ForeignKey is deleted, Django by default emulates the behavior of the SQL constraint ON DELETE CASCADE and also deletes the object containing the ForeignKey.
和
the PROTECT parameter prevents deletion of the referenced object by raising ProtectedError
因此,最简单的步骤应该是删除 on_delete
参数并使用默认行为
basket = models.ForeignKey(Basket)
但是,请查看 ForeignKey model field 的所有可能参数,然后选择适合您的 application/scenario 要求的组合。
更新:
最新的 Django 版本需要 on_delete
。只是不要删除它并添加您想要的参数(如 on_delete=models.CASCADE
)。
您可以先尝试将苹果从 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')
。
我不想回答我的问题,但我的例子过于简单化了。回答的很到位。
在实际产品中涉及 post_save
个信号,例如负责创建 auto_created_basket
。
问题是当我说 myapple.basket = existing_basket
Django 的层没问题,但数据库仍然持有对旧关系的引用。我的解决方案是在我再次保存 myapple
后移动 auto_created_basket.delete()
。