django django-models django-south

Migración de datos de "Many-To-Many" a "Many-To-Many through" en django



django-models django-south (3)

  1. Crea tu modelo intermedio sin campos adicionales, por ahora. Asígnele una restricción única para que coincida con la existente y especifique el nombre de la tabla para que coincida con la existente:

    class CategoryEntry(models.Model): category = models.ForeignKey(Category) entry = models.ForeignKey(Entry) class Meta: db_table=''main_category_entries'' #change main_ to your application unique_together = ((''category'', ''entry''))

  2. Ejecutar la migración del esquema sur.

  3. Edite el script de migración de esquema generado y comente todas las entradas hacia adelante y hacia atrás, ya que reutilizará la tabla de intersección existente. Añadir pass para completar los métodos.

  4. Ejecutar la migración.

  5. Actualizar cualquier código existente. Como se dice en https://docs.djangoproject.com/en/dev/topics/db/models/#many-to-many-relationships , "A diferencia de los campos normales de muchos a muchos, no puede usar agregar, crear, o asignación para crear relaciones ", por lo que deberá modificar cualquier código de aplicación existente, por ejemplo,

    c.entry.add(e)

    podría convertirse:

    try: categoryentry = c.categoryentry_set.get(entry = e) except CategoryEntry.DoesNotExist: categoryentry = CategoryEntry(category=c, entry=e) categoryentry.save()

    y:

    e.category_entries.add(c)

    podría convertirse:

    categoryentry = CategoryEntry(category=c, entry=e) #set extra fields here categoryentry.save()

    y:

    c.entry.remove(e)

    podría convertirse:

    categoryentry = c.categoryentry_set.get(entry = e) categoryentry.delete()

  6. Una vez que se haya realizado esta pseudo migración inicial, debería poder agregar los campos adicionales a la entrada de CategoryEntry y crear otras migraciones de manera normal.

Tengo un modelo

class Category(models.Model): title = models.CharField(...) entry = models.ManyToManyField(Entry,null=True,blank=True, related_name=''category_entries'', )

Que deseo refactorizar para tener datos adicionales con cada relación:

class Category(models.Model): title = models.CharField(...) entry = models.ManyToManyField(Entry,null=True,blank=True, related_name=''category_entries'', through=''CategoryEntry'', )

Pero al sur borra la tabla existente. ¿Cómo puedo preservar las relaciones existentes de mtm?


En las migraciones incorporadas de Django 1.7+, la forma en que se calcula el "estado del código" (es decir, la definición del código de los modelos) es diferente y requiere una solución diferente.

En el sur (Django pre-1.7), el "estado del código" completo se guarda en cada migración, pero en las migraciones incorporadas de Django 1.7+, se deriva de observar todo el conjunto de migraciones, por lo que debe especificar el "código Estado "cambio en una migración sin alterar la base de datos.

Al igual que arriba, esto deberá hacerse en unos pocos pasos.

  1. Crea un modelo intermedio como en la respuesta anterior:

    class CategoryEntry(models.Model): category = models.ForeignKey(Category) entry = models.ForeignKey(Entry) class Meta: db_table = ''main_category_entries'' #change main_ to your application unique_together = (''category'', ''entry'')

  2. Cree una migración automática con django-admin.py makemigrations y modifique el código; mueva la lista de operaciones al argumento state_operations de una operación migrations.SeparateDatabaseAndState y deje la lista database_operations vacía. Debería verse como

    class Migration(migrations.Migration): operations = [ migrations.SeparateDatabaseAndState( state_operations=[ migrations.CreateModel(CategoryEntry..) ... ], database_operations=[] ), ]

  3. Edite CategoryEntry para que contenga lo que desea y cree una nueva migración automática con django-admin.py makemigrations


Lo haría de la siguiente manera:

  1. Agregue la clase CategoryEntry al modelo y realice una migración automática de esquema. Esto agregará una tabla vacía que contiene las propiedades de CategoryEntry . A tener en cuenta, la tabla M2M anterior permanece intacta ya que a through=''CategoryEntry'' aún no se ha agregado.

  2. Realice una migración de datos para copiar todos los datos de la tabla M2M existente a la tabla creada en el paso 1. Para hacerlo, ejecute el comando datamigration y edite los métodos forward() y backward() en el script de migración generado automáticamente.

  3. Ahora agregue a through=''CategoryEntry'' parte through=''CategoryEntry'' (tal como lo deseaba) y realice una migración de esquema. Esto dejará caer la vieja tabla M2M.