【问题标题】:Correct way to delete all MpttModel Entries using Django Manager使用 Django Manager 删除所有 MpttModel 条目的正确方法
【发布时间】:2020-03-23 11:11:21
【问题描述】:

我有一个 Django 模型 (Feature) 子类 MPTTModel。作为外键 MPTT 模型的最佳实践是保留on_delete=PROTECT,努力一次删除所有 MPTT 条目,使用

        Feature.objects.all().delete()

我收到以下错误

django.db.models.deletion.ProtectedError: ("Cannot delete some instances of model 'Feature' because they are referenced through a protected foreign key: 'Feature.parent'"...

我可以先删除所有子节点,然后再删除根节点。但这对我来说似乎没有效率。有没有更好的选择?

【问题讨论】:

    标签: django django-models django-mptt


    【解决方案1】:

    您应该能够通过运行查询以获取所有根节点并删除这些节点来删除所有节点。我不知道您的模型结构,但应该可以使用以下内容:

    root_nodes = Feature.objects.filter(parent__isnull=true)
    root_nodes.delete()
    

    docs 声明删除根节点应该可以工作。

    【讨论】:

      【解决方案2】:

      您可以通过批量删除从叶节点中修剪树:

      from django.db.models import F, Max
      
      max_level = MyModel.objects.all().aggregate(max=Max(F('level')))['max']
      
      while max_level > -1:
          MyModel.objects.filter(level=max_level).delete()
          max_level = max_level - 1
      

      或者您可以使用单个直接 SQL 命令绕过 Django 保护:

      from django.db import connection
      
      with connection.cursor() as cursor:
          cursor.execute("DELETE FROM app_mymodel")
      

      【讨论】:

      • 虽然直接 SQL 可以工作,但这让我质疑为什么原始模型具有 PROTECTED 删除属性开头。听起来预期的行为更类似于CASCADE
      • 就我而言,因为在生产模式下我想避免用户删除带有子节点的节点。但是,当系统仍在测试中时,我想要一种简单的方法来从该特定模型中删除所有记录,而无需更改其原始属性。但你是对的 - 现在应该可以设置 CASCADE 并在某处放置注释以记住在切换到生产模式之前切换回 PROTECT。我只是不喜欢依赖那些笔记。
      猜你喜欢
      • 1970-01-01
      • 2022-01-08
      • 2019-09-13
      • 2015-09-18
      • 2016-04-07
      • 2016-08-07
      • 1970-01-01
      • 1970-01-01
      • 2020-05-15
      相关资源
      最近更新 更多