在Django mod中防止删除

2024-05-09 12:01:53 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个这样的设置(为这个问题简化了):

class Employee(models.Model):
    name = models.CharField(name, unique=True)

class Project(models.Model):
    name = models.CharField(name, unique=True)
    employees = models.ManyToManyField(Employee)

当员工即将被删除时,我想检查他是否与任何项目有关联。如果是,删除应该是不可能的。

我知道信号和如何工作。我可以连接到pre_delete信号,并使其引发类似ValidationError的异常。这样可以防止删除,但表单等并不能很好地处理它。

这似乎是其他人会遇到的情况。我希望有人能指出一个更优雅的解决方案。


Tags: 项目nameprojecttruemodel信号models员工
3条回答

对于那些引用这些具有相同问题且具有ForeignKey关系的问题的人,正确的答案是在ForeignKey关系上使用Djago的on_delete=models.PROTECT字段。这将阻止删除任何具有外键链接的对象。这不适用于ManyToManyField关系(如this问题中所讨论的),但适用于ForeignKey字段。

所以如果模型是这样的,这将防止删除 任何具有一个或多个与其关联的Project对象的Employee对象:

class Employee(models.Model):
    name = models.CharField(name, unique=True)

class Project(models.Model):
    name = models.CharField(name, unique=True)
    employees = models.ForeignKey(Employee, on_delete=models.PROTECT)

文档可以找到HERE

如果您知道永远不会有任何大规模的员工删除尝试,您可以覆盖模型上的delete,并且只有在合法操作时才调用super

不幸的是,任何可能调用queryset.delete()的内容都将直接转到SQL: http://docs.djangoproject.com/en/dev/topics/db/queries/#deleting-objects

但我不认为这是个大问题,因为你是编写这段代码的人,可以确保员工永远不会有任何queryset.delete()。手动调用delete()

我希望删除员工是比较少见的。

def delete(self, *args, **kwargs):
    if not self.related_query.all():
        super(MyModel, self).delete(*args, **kwargs)

我在寻找这个问题的答案,却找不到一个好的答案,这对Model.Model.delete()和QuerySet.delete()都有效。我一直在执行史蒂夫K的解决方案。我使用这个解决方案来确保对象(本例中的Employee)不能以任何方式从数据库中删除,而是设置为inactive。

这是个迟交的答复。。只是为了其他人看我把我的解决方案放在这里。

代码如下:

class CustomQuerySet(QuerySet):
    def delete(self):
        self.update(active=False)


class ActiveManager(models.Manager):
    def active(self):
        return self.model.objects.filter(active=True)

    def get_queryset(self):
        return CustomQuerySet(self.model, using=self._db)


class Employee(models.Model):
    name = models.CharField(name, unique=True)
    active = models.BooleanField(default=True, editable=False)

    objects = ActiveManager()

    def delete(self):
        self.active = False
        self.save()

用法:

Employee.objects.active() # use it just like you would .all()

或者在管理员:

class Employee(admin.ModelAdmin):

    def queryset(self, request):
        return super(Employee, self).queryset(request).filter(active=True)

相关问题 更多 >