2011-11-24 87 views
8

我有三個字段遷移的Django模型unique_together約束

class MyModel(models.Model): 
    a = models.ForeignKey(A) 
    b = models.ForeignKey(B) 
    c = models.ForeignKey(C) 

我要強制執行這些領域之間的唯一約束的模型,發現Django的unique_together,這似乎是解決方案。但是,我已經有了一個現有的數據庫,並且有很多重複項。我知道,因爲unique_together在數據庫級別工作,所以我需要唯一 - 如果行,然後嘗試遷移。

是否有一個很好的方法可以去除重複項(其中重複項具有相同的(A,B,C)),以便我可以運行遷移以獲得unique_together限制?

+0

你有你的模型的任何其他領域(可能影響選擇哪個重複保留)? – second

+0

我有一個created_at時間,可能是最好的指標 – jkeesh

回答

22

如果你很樂意任意選擇一個副本,我認爲以下可能會有所斬斷。也許不是最有效,但很簡單,我想你只需要運行一次。請確認這一切都適用於某些測試數據,以防萬一我做了一些愚蠢的事情,因爲您將要刪除一堆數據。

首先我們找到形成重複的對象組。對於每個組,(任意)選擇一個我們將要保留的「主」。我們選擇的方法是選擇一個具有最低pk

master_pks = MyModel.objects.values('A', 'B', 'C' 
    ).annotate(Min('pk'), count=Count('pk') 
    ).filter(count__gt=1 
    ).values_list('pk__min', flat=True) 

然後我們遍歷每個主,並刪除其所有副本

masters = MyModel.objects.in_bulk(list(master_pks)) 

for master in masters.values(): 
    MyModel.objects.filter(a=master.a, b=master.b, c=master.c 
     ).exclude(pk=master.pk).del_ACCIDENT_PREVENTION_ete() 
+1

我們可以在遷移文件本身做些類似的事情,避免運行額外的腳本嗎? – chhantyal

+1

什麼是'.del_ACCIDENT_PREVENTION_elte()'? – Dusty

+7

在中間添加短語「ACCIDENT_PREVENTION」的'delete',以防止人們在不讀取的情況下通過複製/粘貼代碼而意外刪除東西 – second

相關問題