Django的unique_together与标记对象为“删除”
我正在实现在“Django中标记为删除”中讨论的第一种方法,也就是当一个对象不再活跃时,我会设置一个布尔值来标记它为不活跃。
我选择这种方法的具体原因是,虽然这个对象不再被活跃使用,但它可能仍然在各种记录和报告输出中被引用和显示。我不想让Django的级联删除把旧记录删除掉。
我应该如何确保活跃对象的唯一性呢?
最开始,我想我应该使用unique_together
来在数据库层面上强制执行我的约束。这在我删除一个对象时是可以的,但当我想添加一个同名的新活跃对象时,就会违反唯一性要求。我可以简单地把对象重新标记为活跃,但我其实想要一个新对象。
我希望能有一种方法,让我可以说“当活跃 = True时唯一”。我可以在模型创建代码中强制执行这个,但在数据库层面上强制执行似乎是个更好的主意。
有没有关于这两种方法哪个更好的建议?或者有没有更好的建议?
注意:django-reversion很不错,但完全不适合我的应用,因为我确实需要不时访问“已删除”的对象。
2 个回答
我明白你说的意思,认为 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 执行查询,并访问活跃和非活跃的模型。
你可以设置一个唯一约束:
class Meta:
unique_together = ( ('name', 'active'),)
不过,这样的话,你只能有一个活跃的对象和一个不活跃的对象,且它们的名字必须不同。
如果你把活跃状态设置为一个空布尔字段(NullBooleanField),那么你就可以把活跃状态设为NULL,这样就可以有无限多个不活跃的对象,名字可以相同。至少在PostgreSQL中,NULL值在约束条件下不会被认为是违反约束的。