Django unique_together并将对象标记为“已删除”

时间:2009-11-02 00:49:23

标签: python django database-design django-models

我正在实现"Marking for deletion in Django"中讨论的第一个选项,也就是说,当一个对象不再处于活动状态时,我设置了一个布尔值来将其标记为非活动状态。

我使用此方法的具体原因是,虽然该对象不再处于活动状态,但仍可以在各种记录和报告输出中引用和显示该对象。我不希望Django的涟漪删除删除旧记录。

我应该如何强制执行活动对象的唯一性?

最初,我认为我应该使用unique_together在数据库级别强制执行我的约束。这样可以正常工作,直到我删除一个对象,此时添加一个具有相同名称的新活动对象违反了唯一性要求。我可以简单地将对象重新标记为活动对象,但实际上我想要一个新对象。

我正在寻找能让我说出“当活跃=真实时独特在一起”之类的东西。我可以在模型创建代码中强制执行此操作,但似乎在数据库级别强制执行它是一个更好的主意。

关于哪一项是最佳方法的任何建议?还有更好的建议吗?

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

3 个答案:

答案 0 :(得分:4)

你可以有一个独特的约束:

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

但是,这意味着您只能拥有一个具有相同名称的活动对象和一个非活动对象。

如果激活NullBooleanField,则可以将NULL设置为active,并使(IIRC)具有无限数量的具有相同名称的非活动对象。至少PostgreSQL将NULL值解释为约束的一部分,因为它不会破坏约束。

答案 1 :(得分: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进行创建。然后,仅对活动模型强制执行unique_together。要将模型标记为无效,请执行model.make_inactive而不是前model.active=False。您仍然可以继续对BaseModel执行查询并访问活动和非活动模型。

答案 2 :(得分:0)

设置这样的结构:

class Item(models.Model):
    unique_field = models.CharField(unique=True, null=True)

class DeletedItem(models.Model):
    original = models.OneToOneField(Item)
    original_unique_field = models.CharField()

要删除项目,请创建一个指向原始项目的DeletedItem。将“unique_field”值复制到DeletedItem。然后将Item.unique_field设置为NULL。

这适用于Postgres和sqlite,因为它们是allow NULL's in unique fields。不能说其他DB的。