Django的unique_together与标记对象为“删除”

4 投票
2 回答
2199 浏览
提问于 2025-04-15 15:35

我正在实现在“Django中标记为删除”中讨论的第一种方法,也就是当一个对象不再活跃时,我会设置一个布尔值来标记它为不活跃。

我选择这种方法的具体原因是,虽然这个对象不再被活跃使用,但它可能仍然在各种记录和报告输出中被引用和显示。我不想让Django的级联删除把旧记录删除掉。

我应该如何确保活跃对象的唯一性呢?

最开始,我想我应该使用unique_together来在数据库层面上强制执行我的约束。这在我删除一个对象时是可以的,但当我想添加一个同名的新活跃对象时,就会违反唯一性要求。我可以简单地把对象重新标记为活跃,但我其实想要一个新对象。

我希望能有一种方法,让我可以说“当活跃 = True时唯一”。我可以在模型创建代码中强制执行这个,但在数据库层面上强制执行似乎是个更好的主意。

有没有关于这两种方法哪个更好的建议?或者有没有更好的建议?

注意:django-reversion很不错,但完全不适合我的应用,因为我确实需要不时访问“已删除”的对象。

2 个回答

0

我明白你说的意思,认为 unique together 应该保持在数据库层面。理论上,最好的设计是这样的:不需要依赖于数据库对 unique together 的限制,而是把这个限制当作是这个表的一个永久规则。

基于这个想法,如果区分“活跃”和“非活跃”是在“表层”进行,而不是通过一些复杂的模型操作,那会怎么样呢?

想想下面这个例子:

class BaseModel(models.Model):
    # all of your fields here
    active = models.BooleanField()


class ActiveModel(BaseModel):    
    class Meta:
        unique_together = ('whatever', 'fields')    

    def make_inactive(self):
        # create a new instance of InactiveModel based on
        # this instances's values, then delete this instance


class InactiveModel(BaseModel):
    def make_active(self):
        # create a new instance of InactiveModel based on
        # this instances's values, then delete this instance

这样一来,每当你创建一个新模型时,都是使用 ActiveModel。然后,唯一性限制只会对活跃模型生效。要把一个模型标记为非活跃,你可以用 model.make_inactive,而不是之前的 model.active=False。你仍然可以对 BaseModel 执行查询,并访问活跃和非活跃的模型。

4

你可以设置一个唯一约束:

class Meta:
     unique_together = ( ('name', 'active'),)

不过,这样的话,你只能有一个活跃的对象和一个不活跃的对象,且它们的名字必须不同。

如果你把活跃状态设置为一个空布尔字段(NullBooleanField),那么你就可以把活跃状态设为NULL,这样就可以有无限多个不活跃的对象,名字可以相同。至少在PostgreSQL中,NULL值在约束条件下不会被认为是违反约束的。

撰写回答