如何强制执行条件唯一性约束

时间:2012-06-12 23:16:33

标签: mysql django

假设我有一堆表,其中对象被标记为已删除而不是实际删除。现在,我想强制执行一个约束,即只有一个具有特定字段值的非删除对象,但我可以有多个具有相同字段值的已删除对象。

class Deletable(models.Model):
    deleted = models.BooleanField(default=False)

    class Meta:
       abstract=True

    def soft_delete(self):
       self.deleted=True
       self.save()

class ConcreteModel(Deletable):
    a = models.IntegerField()
    b = models.IntegerField()

    class Meta:
       #wrong because there may have been some deleted rows
       unique_together=('a', 'b')

强制执行约束的最佳方法是什么?

3 个答案:

答案 0 :(得分:1)

在另一个字段中定义您的唯一约束:deleted和您的伪唯一字段。然后,要表示软删除,请将模型的ID分配给deleted;对于未删除的项目,请指定0。

使用这种方法,对于未删除的项目,由于deleted字段具有一致性值,因此多字段唯一约束将有效地忽略deleted的值并强制执行唯一性独特的领域;对于已删除的项目,deleted将被考虑在内,并且由于它是唯一的,因此约束将始终令人满意 - 因此具有相同伪唯一字段值的任意数量的模型都可以共存。

例如,您可能正在寻找以下代码。

class Deletable(models.Model):
    deleted = models.IntegerField(default=0)

    class Meta:
       abstract=True

    def soft_delete(self):
       self.deleted=self.id
       self.save()

class ConcreteModel(Deletable):
    a = models.IntegerField()
    b = models.IntegerField()

    class Meta:
       unique_together=('a', 'b', 'deleted')

答案 1 :(得分:0)

答案 2 :(得分:0)

Django 2.2 以上的版本,可以使用 UniqueConstraint。

在您的模型上使用:

from django.db.models import Q

class ConcreteModel(Deletable):
    a = models.IntegerField()
    b = models.IntegerField()

    class Meta:
        constraints = [
            models.UniqueConstraint(fields=['a', 'b'], condition=Q(deleted=False), name='a_b_unique')]