Migración de datos de "Many-To-Many" a "Many-To-Many through" en django
django-models django-south (3)
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''))
Ejecutar la migración del esquema sur.
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.Ejecutar la migración.
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()
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.
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'')
Cree una migración automática con
django-admin.py makemigrations
y modifique el código; mueva la lista de operaciones al argumentostate_operations
de una operaciónmigrations.SeparateDatabaseAndState
y deje la listadatabase_operations
vacía. Debería verse comoclass Migration(migrations.Migration): operations = [ migrations.SeparateDatabaseAndState( state_operations=[ migrations.CreateModel(CategoryEntry..) ... ], database_operations=[] ), ]
Edite
CategoryEntry
para que contenga lo que desea y cree una nueva migración automática condjango-admin.py makemigrations
Lo haría de la siguiente manera:
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 deCategoryEntry
. A tener en cuenta, la tabla M2M anterior permanece intacta ya que athrough=''CategoryEntry''
aún no se ha agregado.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étodosforward()
ybackward()
en el script de migración generado automáticamente.Ahora agregue a
through=''CategoryEntry''
partethrough=''CategoryEntry''
(tal como lo deseaba) y realice una migración de esquema. Esto dejará caer la vieja tabla M2M.