【问题标题】:Django model ON DELETE CASCADE policy, emulate ON DELETE RESTRICT instead, general solutionDjango 模型 ON DELETE CASCADE 策略,改为模拟 ON DELETE RESTRICT,通用解决方案
【发布时间】:2010-12-27 04:46:10
【问题描述】:

我想删除模型的一个实例,但前提是它没有另一个类的任何其他实例且外键指向它。来自 Django 文档:

当 Django 删除一个对象时,它会模拟 SQL 约束 ON DELETE CASCADE 的行为——换句话说,任何具有指向要删除的对象的外键的对象都将被删除。

在一个给定的例子中:

class TestA(models.Model)
    name = models.CharField()

class TestB(models.Model)
    name = models.CharField()
    TestAs = models.ManyToManyField(TestA)

# More classes with a ManyToMany relationship with TestA
# ........

我想要类似的东西:

tA = TestA(name="testA1")
tB = TestB(name="testB1")
tB.testAs.add(tA)

t = TestA.objects.get(name="testA1")

if is_not_foreignkey(t):
    t.delete()
else:
    print "Error, some instance is using this"

应该打印错误。我知道我可以检查外键集的特定实例,例如在本例中检查 t.TestB_set(),但我正在为任何给定模型寻找更通用的解决方案。

【问题讨论】:

    标签: python django django-models


    【解决方案1】:

    CollectedObjects() 在 Django 1.3 中被移除——这是一个当前的方法:

    from compiler.ast import flatten
    from django.db import DEFAULT_DB_ALIAS
    from django.contrib.admin.util import NestedObjects
    
    def delete_obj_if_no_references(obj):
        collector = NestedObjects(using=DEFAULT_DB_ALIAS)
        collector.collect([obj])
        objs = flatten(collector.nested())
        if len(objs) == 1 and objs[0] is obj:
            obj.delete()
            return True
        return False
    

    【讨论】:

      【解决方案2】:

      我终于用这个Nullable ForeignKeys and deleting a referenced model instance解决了,解决方案如下:

          # Check foreign key references
          instances_to_be_deleted = CollectedObjects()
          object._collect_sub_objects(instances_to_be_deleted)
      
          # Count objects to delete
          count_instances_to_delete = 0
          for k in instances_to_be_deleted.unordered_keys():
              count_instances_to_delete += len(instances_to_be_deleted[k])
      
          if count_instances_to_delete == 1:
              object.delete()
          else:
              pass
      

      【讨论】:

        【解决方案3】:

        检查相关对象的长度

        t=TestA.objects.get(name="textA1")
        if not t.testB_set.all().count():#related members
          t.delete()
        

        【讨论】:

        • 这适用于特定情况,但我想要一个更通用的解决方案,因此我不必为每个模型编写不同的删除测试并在另一个对象引用它时更新它。跨度>
        猜你喜欢
        • 2018-12-02
        • 2014-09-26
        • 2019-07-12
        • 1970-01-01
        • 2015-12-31
        • 1970-01-01
        • 1970-01-01
        • 2018-12-01
        相关资源
        最近更新 更多