使用Django实现具有唯一约束条件的软删除

7

我有这种布局的模型:

class SafeDeleteModel(models.Model):
    .....
    deleted = models.DateTimeField(editable=False, null=True)
    ......

class MyModel(SafeDeleteModel):
    safedelete_policy = SOFT_DELETE

    field1 = models.CharField(max_length=200)
    field2 = models.CharField(max_length=200)
    field3 = models.ForeignKey(MyModel3)
    field4 = models.ForeignKey(MyModel4)
    field5 = models.ForeignKey(MyModel5)

    class Meta:
        unique_together = [['field2', 'field3', 'field4', 'deleted'],]

这里的情景是我不希望用户删除数据,而是将记录隐藏起来。但是,我仍然希望所有未软删除的记录都遵守唯一键约束。基本上,我希望有尽可能多的重复删除记录,但只能存在一个唯一未删除记录。因此,我考虑添加“已删除”字段(由Django-safedelete库提供),但问题在于Django的唯一检查会因为['field2','field3','field4','deleted']这些属性中NULL不等于NULL,并返回"psycopg2.IntegrityError:违反唯一约束条件的重复关键字值" 。

是否有一种方法可以使用与我的Django模型布局相同的方式强制实施unique_together约束?或者直接物理删除记录,然后将其移动到归档数据库,并且如果用户想要恢复记录,软件将在归档中寻找记录并重新创建它?

1个回答

18

是的,从Django 2.2版本开始,你可以在UniqueConstraint中使用条件。

请查看此链接中的文档:https://docs.djangoproject.com/en/2.2/ref/models/constraints/#uniqueconstraint

因此,您的模型将类似于以下内容:

class MyModel(SafeDeleteModel):
    safedelete_policy = SOFT_DELETE

    field1 = models.CharField(max_length=200)
    field2 = models.CharField(max_length=200)
    field3 = models.ForeignKey(MyModel3)
    field4 = models.ForeignKey(MyModel4)
    field5 = models.ForeignKey(MyModel5)

    class Meta:
        constraints = [
            models.UniqueConstraint(
                fields=['field2', 'field3', 'field4'],
                condition=Q(deleted=False),
                name='unique_if_not_deleted')
        ]

如果您正在使用没有此功能的旧版本Django,您可以创建一个带有部分唯一索引的迁移(请查看这里的问题:Postgresql:有条件的唯一约束)。

至于您的第二个问题(删除记录并将其移动到其他地方是否更好),它取决于您的应用程序特性。 如果这些软删除不经常发生且表格仍然比较小,则出于简单起见,我会将记录保留在同一个表格中,但是如果表格中的记录数开始快速增长并且它们影响对该表格的查询性能,则应将记录移至其他地方。 您必须评估复杂性和性能之间的权衡。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接