django-models - migrar - migracion django
migrar el cambio de nombre de campo de django-model sin perder datos (6)
Tengo un proyecto django con una tabla de base de datos que ya contiene datos. Me gustaría cambiar el nombre del campo sin perder ninguno de los datos en esa columna. Mi plan original era simplemente cambiar el nombre de campo del modelo de una manera que en realidad no alteraría el nombre de la tabla db (utilizando el parámetro de la columna db_column
):
El modelo original:
class Foo(models.Model):
orig_name = models.CharField(max_length=50)
El nuevo modelo:
class Foo(models.Model):
name = models.CharField(max_length=50, db_column=''orig_name'')
Pero al ejecutar la schemamigration --auto
de schemamigration --auto
de South, se produce una secuencia de comandos de migración que elimina la columna original, orig_name
y agrega una nueva columna, name
, que tendría el efecto secundario no deseado de eliminar los datos en esa columna. (También estoy confundido sobre por qué South quiere cambiar el nombre de la columna en el db, ya que mi entendimiento de db_column es que permite un cambio al nombre del campo modelo sin cambiar el nombre de la columna de la tabla de la base de datos).
Si no puedo salirse con la suya cambiando el campo de modelo sin cambiar el campo de db, creo que podría hacer un cambio de nombre más directo así:
El modelo original:
class Foo(models.Model):
orig_name = models.CharField(max_length=50)
El nuevo modelo:
class Foo(models.Model):
name = models.CharField(max_length=50)
Independientemente de la estrategia que termine usando (preferiría la primera, pero encontraría la segunda aceptable), mi principal preocupación es asegurarme de no perder los datos que ya están en esa columna.
¿Esto requiere un proceso de varios pasos? (como 1. agregar una columna, 2. migrar los datos de la columna anterior a la nueva columna, y 3. eliminar la columna original) ¿O puedo modificar el script de migración con algo como db.alter_column
?
¿Cuál es la mejor manera de preservar los datos en esa columna al cambiar el nombre de la columna?
Cambiar el nombre del campo mientras se mantiene el campo DB
Agregando una respuesta para Django 1.8+ (con migraciones nativas de Django, en lugar de hacia el sur).
Realice una migración que primero agrega una propiedad db_column
y luego cambia el nombre del campo. Django entiende que el primero es un no-op (porque cambia el db_column
para permanecer igual), y que el segundo es un no-op (porque no hace cambios en el esquema). De hecho, examiné el registro para ver que no había cambios de esquema ...
operations = [
migrations.AlterField(
model_name=''mymodel'',
name=''oldname'',
field=models.BooleanField(default=False, db_column=b''oldname''),
),
migrations.RenameField(
model_name=''mymodel'',
old_name=''oldname'',
new_name=''newname'',
),
]
En realidad, con Django 1.10, simplemente al cambiar el nombre del campo en el modelo y luego ejecutar makemigrations, se identifica inmediatamente la operación (es decir, un campo desapareció, otro apareció en su lugar):
$ ./manage.py makemigrations
Did you rename articlerequest.update_at to articlerequest.updated_at (a DateTimeField)? [y/N] y
Migrations for ''article_requests'':
article_requests/migrations/0003_auto_20160906_1623.py:
- Rename field update_at on articlerequest to updated_at
Es bastante fácil de arreglar. Pero deberá modificar la migración usted mismo.
En lugar de descartar y agregar la columna, use db.rename_column
. Simplemente puede modificar la migración creada por schemamigration --auto
Es posible cambiar el nombre de un campo sin realizar ninguna edición manual de archivos de migración:
- Agregue db_column = OLD_FIELD_NAME al campo original.
- Ejecutar:
python3 manage.py makemigrations
- Cambiar el nombre del campo de OLD_FIELD_NAME a NEW_FIELD_NAME
- Ejecutar:
python3 manage.py makemigrations
Se le pedirá:
¿Le cambió el nombre a MODELO ? OLD_FIELD_NAME a MODELO . NEW_FIELD_NAME (una clave externa )? [y / N] y
Esto generará dos archivos de migración en lugar de uno solo, aunque ambas migraciones se generan automáticamente.
Este procedimiento funciona en Django 1.7+.
Me encontré con esta situación en Django 1.7.7. Terminé haciendo lo siguiente que funcionó para mí.
./manage.py makemigrations <app_name> --empty
Se agregó una subclase simple de migrations.RenameField
que no toca la base de datos:
class RenameFieldKeepDatabaseColumn(migrations.RenameField):
def database_backwards(self, app_label, schema_editor, from_state, to_state):
pass
def database_forwards(self, app_label, schema_editor, from_state, to_state):
pass
Me he encontrado con esta situación. Quería cambiar los nombres de los campos en el modelo pero mantener los nombres de las columnas iguales.
La forma en que lo hice es hacer schemamigration --empty [app] [some good name for the migration]
. El problema es que, en lo que concierne a South, cambiar los nombres de campo en el modelo es un cambio que necesita manejar. Entonces, se debe crear una migración. Sin embargo, sabemos que no hay nada que hacer en el lado de la base de datos. Por lo tanto, una migración vacía evita realizar operaciones innecesarias en la base de datos y, sin embargo, satisface la necesidad de South de manejar lo que considera un cambio.
Tenga en cuenta que si utiliza datos de loaddata
o utiliza el dispositivo de fijación de prueba de Django (que utiliza datos de loaddata
detrás de las escenas). Deberá actualizar los dispositivos para usar el nuevo nombre de campo porque los dispositivos se basan en los nombres de los campos del modelo, no en los nombres de los campos de la base de datos.
Para los casos en los que los nombres de las columnas cambian en la base de datos, nunca recomiendo el uso db.rename_column
para las migraciones de columnas. Uso el método descrito por sjh en esta respuesta :
He agregado la nueva columna como una migración de esquema, luego creé una migración de datos para mover valores al nuevo campo, luego una segunda migración de esquema para eliminar la columna anterior
Como noté en un comment sobre esa pregunta, el problema con db.rename_column
es que no cambia el nombre de las restricciones junto con la columna. No sé si el problema es meramente cosmético o si esto significa que una migración futura puede fallar porque no puede encontrar una restricción.