Convertir campo ForeingKey a ManytoMany

  
18 de Octubre de 2014   0  

Muchas veces nos podríamos ver en el caso en que creamos un campo que inicialmente es un ForeignKey a un modelo pero luego necesitamos convertirlo a ManytoMany.

 

En ese caso si modificamos nuestro modelo y hacemos un migrate perderemos todos los datos relacionados al ForeignKey. Aquí aprenderemos como podemos solucionar este proceso de una forma muy sencilla.

Imaginemos que tenemos nuestro modelo “Descuento” que tiene un campo ForeignKey a un modelo llamado “Habitación”. (Un descuento está asociado a una habitación)

1
2
3
class Habitacion(models.Model):
    codigo = models.CharField(max_length=200)
    nombre = models.CharField(max_length=200)
1
2
3
class Descuento(models.Model):
    codigo = models.CharField(max_length=100)
    habitacion = models.ForeignKey(Habitacion)

1.- Agregamos un nuevo campo ManyToMany hacia Habitaciones en el modelo de Descuento

1
habitaciones_todas = models.ManyToManyField(Habitacion related_name='habitaciones_info')

Recordamos agregar el related_name igual si no lo ponemos al hacer el schemamigration nos lo pedirá.

2.- Empezamos a crear la migración usando el comando

1
python manage.py schemamigration app1 --auto

En este punto se nos ha generado un fichero en la carpeta migrations, con la migración pendiente

3.- Editamos el fichero generado de la migración, y nos vamos al metodo forward
al final del metodo agregamos un for para asignar los valores de habitation ahabitacion_todas que es nuestro ManyToMany

1
2
3
for dto in Descuento.objects.all():
        dto.habitacion_todas.add(dto.habitacion)
        dto.save()

4.- Ahora podemos ejecutar el migrate

1
python manage.py migrate app1

En éste punto ya nos creo el campo habitaciones_todas con los valores de habitación.

5.- Ahora debemos eliminar el campo de habitación y cambiarle el nombre al campo habitaciones_todas por habitación, pero lo haremos en 2 pasos.

primero Eliminamos el campo habitación y ejecutamos la migración

1
2
python manage.py schemamigration app1 --auto
python manage.py migrate app1

y Ahora modificamos el nombre del campo ManyToMany (habitacion_todas) por habitación y volvemos a generar la migration pero esta vez solo haremos el schemamigration (No ejecutar el migrate)

1
python manage.py schemamigration app1 --auto

6.- Ahora debemos ir al nuevo fichero de migracion que nos ha creado y modificar todo el metodo forward, ya que lo que hará será eliminar la tabla y volver a crearla eliminando la data y lo que habremos hecho no habrá servido de nada. Entonces debemos indicarle que no la elimine sino le cambie el nombre. dejáramos el método algo así:

1
2
db.delete_unique('app1_habitacion_todas', ['descuento_id''habitacion_id']) (Ya que el campo es opcional)
db.rename_table('app1_habitacion_todas''app1_habitacion')

7.- Ahora podemos hacer el ultimo migrate

1
python manage.py migrate app1

Saludos.



Alex Dzul

FullStack Python / Django Developer. #jslove

Temas relacionados