2011-11-24 14 views
8

Ho un modello con tre campiMigrate Django modello di vincolo unique_together

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

voglio far rispettare un vincolo unica tra questi campi, e trovò di Django unique_together, che sembra essere la soluzione. Tuttavia, ho già un database esistente e ci sono molti duplicati. So che dal momento che unique_together funziona a livello di database, ho bisogno di unificare le righe e quindi provare una migrazione.

C'è un buon modo per rimuovere i duplicati (dove un duplicato ha lo stesso (A, B, C)) in modo che possa eseguire la migrazione per ottenere il contstraint unique_together?

+0

avete qualsiasi altro campo sul vostro modello (che possono influenzare la scelta di quale duplicato da conservare)? – second

+0

ho un tempo created_at che probabilmente sarebbe l'indicatore migliore – jkeesh

risposta

22

Se sei felice di scegliere uno dei duplicati arbitrariamente, penso che il seguente potrebbe fare il trucco. Forse non è il più efficiente ma abbastanza semplice e immagino che tu debba solo farlo funzionare una volta. Per favore verifica che tutto funzioni su alcuni dati di test nel caso in cui abbia fatto qualcosa di stupido, dato che stai per eliminare un gruppo di dati.

Prima troviamo gruppi di oggetti che formano duplicati. Per ogni gruppo, (arbitrariamente) scegli un "maestro" che manterremo. Il nostro metodo scelto è quello di scegliere quello con il più basso 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) 

abbiamo poi un ciclo su ogni master, e cancellare tutti i suoi duplicati

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

Possiamo fare qualcosa di simile nel file di migrazione stesso che eviterebbe di dover eseguire script aggiuntivi? – chhantyal

+1

Che cosa è '.del_ACCIDENT_PREVENTION_elte()'? – Dusty

+7

'delete' con la frase' ACCIDENT_PREVENTION' aggiunto nel mezzo per evitare che le persone cancellino accidentalmente delle cose copiando/incollando il codice senza leggerlo – second

Problemi correlati