2011-11-24 13 views
8

que tiene un modelo con tres camposmodelo de Django migrar a la restricción unique_together

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

Quiero hacer cumplir una restricción única entre estos campos, y se encontró de unique_together Django, que parece ser la solución. Sin embargo, ya tengo una base de datos existente, y hay muchos duplicados. Sé que como el unique_together funciona en el nivel de la base de datos, necesito especificar las filas y luego intentar una migración.

¿Hay una buena manera de eliminar duplicados (donde un duplicado tiene el mismo (A, B, C)) para que pueda ejecutar la migración para obtener la contstraint unique_together?

+0

tienes cualquier otro campo en el modelo (que puede afectar a la elección de qué duplicar para mantener)? – second

+0

tengo un tiempo created_at que probablemente sea el mejor indicador – jkeesh

Respuesta

22

Si está feliz de elegir uno de los duplicados arbitrariamente, creo que lo siguiente podría ser el truco. Quizás no sea lo más eficiente pero lo suficientemente simple y supongo que solo necesita ejecutar esto una vez. Por favor verifique que todo esto funcione usted mismo en algunos datos de prueba en caso de que haya hecho algo tonto, ya que está a punto de eliminar una gran cantidad de datos.

Primero encontramos grupos de objetos que forman duplicados. Para cada grupo, (arbitrariamente) elija un "maestro" que vamos a guardar. Nuestro método elegido es escoger el que tiene más bajo 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) 

entonces un bucle sobre cada maestro, y eliminar todos sus duplicados

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

¿Podemos hacer algo similar en el archivo de migración, lo que evitaría tener que ejecutar un script adicional? – chhantyal

+1

¿Qué es '.del_ACCIDENT_PREVENTION_elte()'? – Dusty

+7

'eliminar' con la frase' ACCIDENT_PREVENTION' agregado en el medio para evitar que las personas borren accidentalmente cosas copiando/pegando el código sin leerlo – second

Cuestiones relacionadas