2009-11-02 32 views
2

我正在實施"Marking for deletion in Django"中討論的第一個選項,即當對象不再處於活動狀態時,我設置一個布爾值將其標記爲非活動狀態。Django unique_together並將對象標記爲「已刪除」

我使用這種方法的具體原因是,雖然對象不再處於活動使用狀態,但它仍可能被引用並顯示在各種記錄和報告輸出中。我不希望Django的漣漪刪除來刪除舊記錄。

我應該如何去執行活動對象的唯一性?

最初,我以爲我應該使用unique_together來強制執行我在數據庫級別的約束。這工作正常,直到我刪除一個對象,此時添加一個具有相同名稱的新活動對象違反了唯一性要求。我可以簡單地將對象重新標記爲活動對象,但我實際上需要一個新對象。

我在找東西,讓我說一些像「唯一一起,當活動=真」。我可以在模型創建代碼中強制執行此操作,但似乎在數據庫級別強制執行它是一個更好的主意。

任何有關這些是最好的方法的建議?有更好的建議嗎?

注意:django-reversion很酷,但完全不適合我的應用程序,因爲我需要不時訪問「已刪除」的對象。

回答

4

你可以有一個唯一約束:

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

然而,這意味着你只能有一個活動,並具有相同名稱的一個不活動的對象。

如果您使NullBooleanField處於活動狀態,那麼您可以使用NULL作爲活動狀態,並且使(IIRC)具有無限數量的非活動狀態的對象具有相同的名稱。至少,PostgreSQL將NULL值解釋爲約束的一部分,因爲不會破壞約束。

+0

postgresql docs說:「...這兩個空值在這個比較中不被認爲是相等的,這意味着即使存在一個唯一的約束,也可以存儲包含至少一個空值的重複行受限制的列「。 http://www.postgresql.org/docs/8.2/static/ddl-constraints.html – 2009-11-02 02:05:13

+0

MySQL的處理方式類似: 「一個UNIQUE索引創建一個約束條件,使得索引中的所有值都必須是不同的。如果您嘗試添加一個鍵值與現有行匹配的新行,對於所有引擎,UNIQUE索引允許爲包含NULL的列創建多個NULL值。「 http://dev.mysql.com/doc/refman/5.4/en/create-table.html – jnns 2011-04-27 13:12:44

1

我想我明白你從哪裏來,當你說unique together應該保持在數據庫級別。在理論上最好的情況下,最好的設計將不依賴於理解unique together的基礎DB強制執行,而是作爲該約束是該表的永久規則。

根據這個想法工作,如果主動/非主動發生在「桌面級」而不是一些奇特的模型黑客行爲之間的區別?

考慮以下幾點:

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執行查詢並訪問活動和非活動模型。

+1

這種方法的問題是相關的值。如果我有一個外鍵給BaseModel,刪除一個ActiveModel對象並將它重新創建爲一個InactiveModel會破壞這些鏈接,如果我沒有在整個地方進行廣泛的「修復」。 – 2009-11-02 02:02:46

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。然後設置你的物品。unique_field爲NULL。

這適用於Postgres和sqlite,因爲它們allow NULL's in unique fields。不能說其他數據庫的。