Estoy planeando cambiar el nombre de varios modelos en un proyecto Django existente donde hay muchos otros modelos que tienen relaciones de clave externa con los modelos que me gustaría cambiar el nombre. Estoy bastante seguro de que esto requerirá múltiples migraciones, pero no estoy seguro del procedimiento exacto.
Digamos que empiezo con los siguientes modelos dentro de una aplicación Django llamada myapp
:
class Foo(models.Model):
name = models.CharField(unique=True, max_length=32)
description = models.TextField(null=True, blank=True)
class AnotherModel(models.Model):
foo = models.ForeignKey(Foo)
is_awesome = models.BooleanField()
class YetAnotherModel(models.Model):
foo = models.ForeignKey(Foo)
is_ridonkulous = models.BooleanField()
Quiero cambiar el nombre del Foo
modelo porque el nombre realmente no tiene sentido y está causando confusión en el código, y Bar
sería un nombre mucho más claro.
Por lo que he leído en la documentación de desarrollo de Django, estoy asumiendo la siguiente estrategia de migración:
Paso 1
Modificar models.py
:
class Bar(models.Model): # <-- changed model name
name = models.CharField(unique=True, max_length=32)
description = models.TextField(null=True, blank=True)
class AnotherModel(models.Model):
foo = models.ForeignKey(Bar) # <-- changed relation, but not field name
is_awesome = models.BooleanField()
class YetAnotherModel(models.Model):
foo = models.ForeignKey(Bar) # <-- changed relation, but not field name
is_ridonkulous = models.BooleanField()
Tenga en cuenta que el AnotherModel
nombre del campo foo
no cambia, pero la relación se actualiza con el Bar
modelo. Mi razonamiento es que no debería cambiar demasiado de una vez y que si cambiara este nombre de campo bar
correría el riesgo de perder los datos en esa columna.
Paso 2
Crea una migración vacía:
python manage.py makemigrations --empty myapp
Paso 3
Edite la Migration
clase en el archivo de migración creado en el paso 2 para agregar la RenameModel
operación a la lista de operaciones:
class Migration(migrations.Migration):
dependencies = [
('myapp', '0001_initial'),
]
operations = [
migrations.RenameModel('Foo', 'Bar')
]
Paso 4
Aplicar la migración:
python manage.py migrate
Paso 5
Edite los nombres de campo relacionados en models.py
:
class Bar(models.Model):
name = models.CharField(unique=True, max_length=32)
description = models.TextField(null=True, blank=True)
class AnotherModel(models.Model):
bar = models.ForeignKey(Bar) # <-- changed field name
is_awesome = models.BooleanField()
class YetAnotherModel(models.Model):
bar = models.ForeignKey(Bar) # <-- changed field name
is_ridonkulous = models.BooleanField()
Paso 6
Crea otra migración vacía:
python manage.py makemigrations --empty myapp
Paso 7
Edite la Migration
clase en el archivo de migración creado en el paso 6 para agregar las RenameField
operaciones para cualquier nombre de campo relacionado a la lista de operaciones:
class Migration(migrations.Migration):
dependencies = [
('myapp', '0002_rename_fields'), # <-- is this okay?
]
operations = [
migrations.RenameField('AnotherModel', 'foo', 'bar'),
migrations.RenameField('YetAnotherModel', 'foo', 'bar')
]
Paso 8
Aplicar la 2da migración:
python manage.py migrate
Además de actualizar el resto del código (vistas, formularios, etc.) para reflejar los nuevos nombres de variables, ¿es así básicamente cómo funcionaría la nueva funcionalidad de migración?
Además, esto parece muchos pasos. ¿Se pueden condensar las operaciones de migración de alguna manera?
¡Gracias!
fuente
apps.get_model
. Me tomó mucho tiempo resolver eso../manage.py makemigrations myapp
comando le preguntará si cambió el nombre de su modelo. Por ejemplo: ¿Cambiaste el nombre del modelo myapp.Foo a Bar? [y / N] Si responde 'y', su migración contendrá losmigration.RenameModel('Foo', 'Bar')
mismos recuentos para los campos renombrados :-)manage.py makemigrations myapp
aún puede fallar: "Puede que tenga que agregar esto manualmente si cambia el nombre del modelo y algunos de sus campos a la vez; en el autodetector, parecerá que eliminó un modelo con el nombre anterior y agregó uno nuevo con un nombre diferente y la migración que crea perderá los datos de la tabla anterior ". Django 2.1 Docs Para mí, fue suficiente crear una migración vacía, agregarle el nombre del modelo y luego ejecutarlamakemigrations
como de costumbre.Al principio, pensé que el método de Fiver funcionó para mí porque la migración funcionó bien hasta el paso 4. Sin embargo, los cambios implícitos 'ForeignKeyField (Foo)' en 'ForeignKeyField (Bar)' no estaban relacionados en ninguna migración. Es por eso que la migración falló cuando quería cambiar el nombre de los campos de relación (paso 5-8). Esto podría deberse al hecho de que mi 'AnotherModel' y 'YetAnotherModel' se envían en otras aplicaciones en mi caso.
Así que logré cambiar el nombre de mis modelos y campos de relación siguiendo los siguientes pasos:
Adapte el método de esto y particularmente el truco de otranzer.
Entonces, como Fiver, digamos que tenemos en myapp :
Y en myotherapp :
Paso 1:
Transforme cada OneToOneField (Foo) o ForeignKeyField (Foo) en IntegerField (). (Esto mantendrá la identificación del objeto Foo relacionado como valor del campo entero).
Luego
Paso 2: (como el paso 2-4 de Fiver)
Cambiar el nombre del modelo
Crea una migración vacía:
Luego edítalo como:
Finalmente
Paso 3:
Transforme su IntegerField () en su ForeignKeyField anterior o OneToOneField pero con el nuevo Modelo de barra. (El campo entero anterior estaba almacenando la identificación, por lo que django lo comprende y restablece la conexión, lo cual es genial).
Entonces hazlo:
Muy importante, en este paso debe modificar cada nueva migración y agregar la dependencia de las migraciones de RenameModel Foo-> Bar. Entonces, si AnotherModel y YetAnotherModel están en myotherapp, la migración creada en myotherapp debe verse así:
Luego
Paso 4:
Eventualmente puedes renombrar tus campos
y luego renombrar automáticamente
(Django debería preguntarle si realmente cambió el nombre del modelo, diga sí)
¡Y eso es!
Esto funciona en Django1.8
fuente
IntegerField
. Esto funcionó perfectamente para mí y tiene la ventaja adicional de que se recrean con el nombre correcto. ¡Naturalmente, recomendaría revisar todas las migraciones antes de ejecutarlas!ForeignKey
s toIntegerField
s me salvó el día hoy!Necesitaba hacer lo mismo y seguir. Cambié el modelo de una vez (pasos 1 y 5 juntos de la respuesta de Fiver). Luego creó una migración de esquema, pero la editó para que sea así:
Esto funcionó perfectamente. Todos mis datos existentes aparecieron, todas las otras tablas hicieron referencia a Bar bien.
desde aquí: https://hanmir.wordpress.com/2012/08/30/rename-model-django-south-migration/
fuente
Para Django 1.10, logré cambiar dos nombres de clase de modelo (incluida una ForeignKey y con datos) simplemente ejecutando Makemigrations y luego Migrate para la aplicación. Para el paso Makemigrations, tuve que confirmar que quería cambiar los nombres de las tablas. Migrar cambió los nombres de las tablas sin ningún problema.
Luego cambié el nombre del campo ForeignKey para que coincida, y Makemigrations me pidió nuevamente que confirmara que quería cambiar el nombre. Migrar que hizo el cambio.
Así que tomé esto en dos pasos sin ninguna edición especial de archivos. Al principio recibí errores porque olvidé cambiar el archivo admin.py, como lo mencionó @wasibigeek.
fuente
También enfrenté el problema como v.thorey describió y descubrí que su enfoque es muy útil, pero se puede condensar en menos pasos, que en realidad son los pasos 5 a 8 como Fiver describió sin los pasos 1 a 4, excepto que el paso 7 debe cambiarse como mi debajo del paso 3. Los pasos generales son los siguientes:
Paso 1: edite los nombres de campo relacionados en models.py
Paso 2: crea una migración vacía
Paso 3: edite la clase de migración en el archivo de migración creado en el paso 2
Paso 4: aplique la migración
Hecho
PD: he probado este enfoque en Django 1.9
fuente
Estoy usando Django versión 1.9.4
He seguido los siguientes pasos: -
Acabo de cambiar el nombre del modelo oldName a NewName Run
python manage.py makemigrations
. Le pedirá queDid you rename the appname.oldName model to NewName? [y/N]
seleccione YCorre
python manage.py migrate
y te pediráLos siguientes tipos de contenido son obsoletos y deben eliminarse:
También se eliminarán los objetos relacionados con estos tipos de contenido mediante una clave externa. ¿Estás seguro de que deseas eliminar estos tipos de contenido? Si no está seguro, responda 'no'.
Cambia el nombre y migra todos los datos existentes a una nueva tabla con nombre para mí.
fuente
Desafortunadamente, encontré problemas (cada django 1.x) con la migración de cambio de nombre que dejan los viejos nombres de tablas en la base de datos.
Django ni siquiera intenta nada en la vieja mesa, solo cambia el nombre de su propio modelo. El mismo problema con las claves foráneas y los índices en general: Django no realiza un seguimiento adecuado de los cambios.
La solución más simple (solución alternativa):
La solución real (una manera fácil de cambiar todos los índices, restricciones, desencadenantes, nombres, etc. en 2 confirmaciones, sino más bien para tablas más pequeñas ):
cometer A:
Bar
. (incluidas todas las relaciones en el esquema)En la preparación de migración
RunPython
, que copia datos de Foo a Bar (inclusoid
de Foo)cometer B: (sin prisa, hágalo cuando se migra un equipo completo)
Foo
limpieza adicional:
error en Django:
fuente
Solo quería confirmar y agregar el comentario de Césaro. Django 2.0 parece hacer esto automáticamente ahora.
Estoy en Django 2.2.1, todo lo que tenía que hacer era cambiar el nombre del modelo y ejecutarlo
makemigrations
.Aquí me pregunta si había cambiado el nombre de la clase específica de
A
aB
, elegí sí y ejecuté migrate y todo parece funcionar.Tenga en cuenta que no cambié el nombre del modelo anterior en ningún archivo dentro de la carpeta del proyecto / migraciones.
fuente
Necesitaba cambiar el nombre de un par de tablas. Pero Django solo notó un cambio de nombre de modelo. Eso sucedió porque Django itera sobre los modelos agregados y luego eliminados. Para cada par, verifica si son de la misma aplicación y tienen campos idénticos . Solo una tabla no tenía claves foráneas para cambiar el nombre de las tablas (las claves foráneas contienen el nombre de clase de modelo, como recordará). En otras palabras, solo una tabla no tenía cambios de campo. Por eso se notó.
Por lo tanto, la solución es cambiar el nombre de una tabla a la vez, cambiar el nombre de la clase de modelo
models.py
, posiblementeviews.py
, y realizar una migración. Después de eso, inspeccione su código para otras referencias (nombres de clase de modelo, nombres relacionados (consulta), nombres de variables). Realice una migración, si es necesario. Luego, opcionalmente combine todas estas migraciones en una (asegúrese de copiar también las importaciones).fuente
Haría palabras de @ceasaro, mías en su comentario sobre esta respuesta .
Las versiones más recientes de Django pueden detectar cambios y preguntar qué se hizo. También agregaría que Django podría mezclar el orden de ejecución de algunos comandos de migración.
Sería aconsejable aplicar los cambios pequeños y ejecutar
makemigrations
ymigrate
y si el error se produce el archivo de migración puede ser editado.Se puede cambiar el orden de ejecución de algunas líneas para evitar errores.
fuente
migrations.SeparateDatabaseAndState
puede ayudar?Si está utilizando un buen IDE como PyCharm, puede hacer clic derecho en el nombre del modelo y hacer un refactorizador -> cambiar el nombre. Esto le ahorra la molestia de revisar todo el código que hace referencia al modelo. Luego ejecuta makemigrations y migra. Django 2+ simplemente confirmará el cambio de nombre.
fuente
Actualicé Django de la versión 10 a la versión 11:
(
-U
para "actualización") y resolvió el problema.fuente