python - makemigrations - reset all migrations
Estrategia de migraciĆ³n de Django para cambiar el nombre de un modelo y campos de relaciĆ³n (9)
Estoy planeando cambiar el nombre de varios modelos en un proyecto existente de Django donde hay muchos otros modelos que tienen relaciones de clave externa con los modelos que me gustaría cambiar de nombre. Estoy bastante seguro de que esto requerirá migraciones múltiples, pero no estoy seguro del procedimiento exacto.
Digamos que empiezo con los siguientes modelos dentro de una aplicación de 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 modelo de Foo
porque el nombre realmente no tiene sentido y está causando confusión en el código, y Bar
daría un nombre mucho más claro.
Según lo que he leído en la documentación de desarrollo de Django, asumo 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 nombre del campo AnotherModel
para foo
no cambia, pero la relación se actualiza al modelo de Bar
. Mi razonamiento es que no debería cambiar demasiado a la vez y que si cambiara el nombre de este campo a " 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 clase de Migration
en el archivo de migración creado en el paso 2 para agregar la operación RenameModel
a la lista de operaciones:
class Migration(migrations.Migration):
dependencies = [
(''myapp'', ''0001_initial''),
]
operations = [
migrations.RenameModel(''Foo'', ''Bar'')
]
Etapa 4
Aplicar la migración:
python manage.py migrate
Paso 5
Edite los nombres de los campos 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
Crear otra migración vacía:
python manage.py makemigrations --empty myapp
Paso 7
Edite la clase de Migration
en el archivo de migración creado en el paso 6 para agregar las operaciones de RenameField
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 segunda 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 una gran cantidad de pasos. ¿Pueden las operaciones de migración condensarse de alguna manera?
¡Gracias!
Actualicé Django de la versión 10 a la versión 11:
sudo pip install -U Django
( -U
para "actualización") y resolvió el problema.
Al principio, pensé que el método de Fiver me funcionaba porque la migración funcionó bien hasta el paso 4. Sin embargo, los cambios implícitos ''ForeignKeyField (Foo)'' en ''ForeignKeyField (Bar)'' no se relacionaron en ninguna migración. Es por esto que la migración falló cuando quise cambiar el nombre de los campos de relación (paso 5-8). Esto podría deberse al hecho de que mi ''OtroModelo'' y ''OtroModelo'' se envían en otras aplicaciones en mi caso.
Así que me las arreglé para cambiar el nombre de mis modelos y campos de relación siguiendo estos pasos:
Adapte el método de this y particularmente el truco de otranzer.
Así que, como Fiver, digamos que tenemos en myapp :
class Foo(models.Model):
name = models.CharField(unique=True, max_length=32)
description = models.TextField(null=True, blank=True)
Y en myotherapp :
class AnotherModel(models.Model):
foo = models.ForeignKey(Foo)
is_awesome = models.BooleanField()
class YetAnotherModel(models.Model):
foo = models.ForeignKey(Foo)
is_ridonkulous = models.BooleanField()
Paso 1:
Transforma cada OntToOneField (Foo) o ForeignKeyField (Foo) en IntegerField (). (Esto mantendrá la identificación del objeto Foo relacionado como valor del campo entero).
class AnotherModel(models.Model):
foo = models.IntegerField()
is_awesome = models.BooleanField()
class YetAnotherModel(models.Model):
foo = models.IntegerField()
is_ridonkulous = models.BooleanField()
Entonces
python manage.py makemigrations
python manage.py migrate
Paso 2: (como los pasos 2-4 de Fiver)
Cambiar el nombre del modelo
class Bar(models.Model): # <-- changed model name
name = models.CharField(unique=True, max_length=32)
description = models.TextField(null=True, blank=True)
Crea una migración vacía:
python manage.py makemigrations --empty myapp
Luego edítalo como:
class Migration(migrations.Migration):
dependencies = [
(''myapp'', ''0001_initial''),
]
operations = [
migrations.RenameModel(''Foo'', ''Bar'')
]
Finalmente
python manage.py migrate
Paso 3:
Transformar Vuelve tu IntegerField () en su ForeignKeyField anterior, OneToOneField pero con el nuevo Bar Model. (El integerfield anterior almacenaba el id, por lo que django lo entiende y restablece la conexión, lo cual es genial).
class AnotherModel(models.Model):
foo = models.ForeignKey(Bar)
is_awesome = models.BooleanField()
class YetAnotherModel(models.Model):
foo = models.ForeignKey(Bar)
is_ridonkulous = models.BooleanField()
Entonces hazlo:
python manage.py makemigrations
Muy importante, en este paso debe modificar cada nueva migración y agregar la dependencia a las migraciones de RenameModel Foo-> Bar. Entonces, si AnotherModel y YetAnotherModel están en myotherapp, la migración creada en myotherapp debe verse así:
class Migration(migrations.Migration):
dependencies = [
(''myapp'', ''00XX_the_migration_of_myapp_with_renamemodel_foo_bar''),
(''myotherapp'', ''00xx_the_migration_of_myotherapp_with_integerfield''),
]
operations = [
migrations.AlterField(
model_name=''anothermodel'',
name=''foo'',
field=models.ForeignKey(to=''myapp.Bar''),
),
migrations.AlterField(
model_name=''yetanothermodel'',
name=''foo'',
field=models.ForeignKey(to=''myapp.Bar'')
),
]
Entonces
python manage.py migrate
Etapa 4:
Eventualmente puedes cambiar el nombre de tus campos
class AnotherModel(models.Model):
bar = models.ForeignKey(Bar) <------- Renamed fields
is_awesome = models.BooleanField()
class YetAnotherModel(models.Model):
bar = models.ForeignKey(Bar) <------- Renamed fields
is_ridonkulous = models.BooleanField()
y luego hacer un cambio de nombre automático
python manage.py makemigrations
(django debería preguntarle si cambió el nombre del modelo, diga sí)
python manage.py migrate
¡Y eso es!
Esto funciona en Django1.8
Desafortunadamente, encontré problemas (cada django 1.x) con el cambio de nombre de la migración que deja nombres de tablas antiguas en db (ni siquiera intente con nada en la tabla anterior, simplemente cambie el nombre del modelo).
Solución para ese caso:
class Foo(models.Model):
name = models.CharField(unique=True, max_length=32)
...
Bar = Foo
Entonces, cuando probé esto, parece que puedes condensar los pasos 3 a 7:
class Migration(migrations.Migration):
dependencies = [
(''myapp'', ''0001_initial''),
]
operations = [
migrations.RenameModel(''Foo'', ''Bar''),
migrations.RenameField(''AnotherModel'', ''foo'', ''bar''),
migrations.RenameField(''YetAnotherModel'', ''foo'', ''bar'')
]
Es posible que obtenga algunos errores si no actualiza los nombres donde se importaron, por ejemplo, admin.py e incluso archivos de migración más antiguos (!).
Actualización : Como menciona ceasaro , las versiones más nuevas de Django generalmente pueden detectar y preguntar si se cambia el nombre de un modelo. manage.py makemigrations
primero manage.py makemigrations
y luego verifique el archivo de migración.
Estoy usando la versión 1.9.4 de Django
He seguido los siguientes pasos:
Acabo de cambiar el nombre del modelo oldName por NewName Ejecutar python manage.py makemigrations
. Te preguntará Did you rename the appname.oldName model to NewName? [y/N]
Did you rename the appname.oldName model to NewName? [y/N]
seleccione Y
Ejecute python manage.py migrate
y le preguntará por
Los siguientes tipos de contenido son obsoletos y deben eliminarse:
appname | oldName
appname | NewName
Cualquier objeto relacionado con estos tipos de contenido por una clave externa también será eliminado. ¿Seguro que quieres eliminar estos tipos de contenido? Si no está seguro, responda ''no''.
Type ''yes'' to continue, or ''no'' to cancel: Select No
Renombre y migre todos los datos existentes a la nueva tabla nombrada para mí.
Necesitaba cambiar el nombre de un par de tablas. Pero Django solo notó un cambio de nombre de modelo. Eso sucedió porque Django repite 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 externas contienen el nombre de la clase de modelo, como recordará). En otras palabras, solo una tabla no tenía cambios de campo. Por eso fue notado.
Por lo tanto, la solución es cambiar el nombre de una tabla a la vez, cambiando el nombre de la clase de modelo en models.py
, posiblemente views.py
, y realizando una migración. Después de eso, inspeccione su código para ver otras referencias (nombres de clases de modelos, nombres relacionados (consultas), nombres de variables). Realice una migración, si es necesario. Luego, opcionalmente combine todas estas migraciones en una (asegúrese de copiar las importaciones también).
Necesitaba hacer lo mismo. Cambié el modelo de una vez (es decir, paso 1 y paso 5 juntos). Luego creó una migración de esquema pero la editó para que sea ésta:
class Migration(SchemaMigration):
def forwards(self, orm):
db.rename_table(''Foo'',''Bar'')
def backwards(self, orm):
db.rename_table(''Bar'',''Foo'')
Esto funcionó perfectamente. Aparecieron todos mis datos existentes, todas las otras tablas a las que se hace referencia son Bar bien.
desde aquí: https://hanmir.wordpress.com/2012/08/30/rename-model-django-south-migration/
Para Django 1.10, logré cambiar dos nombres de clase de modelo (incluida una ForeignKey y con datos) simplemente ejecutando Makemigrations y luego Migrando para la aplicación. Para el paso de Makemigrations, tuve que confirmar que quería cambiar los nombres de la tabla. Migrate cambió los nombres de las tablas sin problemas.
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 hacer el cambio.
Así que tomé esto en dos pasos sin ninguna edición especial de archivos. Obtuve errores al principio porque olvidé cambiar el archivo admin.py, como lo menciona @wasibigeek.
También me enfrenté al problema como describió v.thorey y encontré que su enfoque es muy útil, pero se puede resumir en menos pasos, que en realidad son del 5 al 8 como se describió en Fiver sin los pasos 1 a 4, excepto que el paso 7 debe cambiarse debajo del paso 3. Los pasos generales son los siguientes:
Paso 1: edite los nombres de los campos 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 2: crea una migración vacía
python manage.py makemigrations --empty myapp
Paso 3: edite la clase de migración en el archivo de migración creado en el paso 2
class Migration(migrations.Migration):
dependencies = [
(''myapp'', ''0001_initial''),
]
operations = [
migrations.AlterField(
model_name=''AnotherModel'',
name=''foo'',
field=models.IntegerField(),
),
migrations.AlterField(
model_name=''YetAnotherModel'',
name=''foo'',
field=models.IntegerField(),
),
migrations.RenameModel(''Foo'', ''Bar''),
migrations.AlterField(
model_name=''AnotherModel'',
name=''foo'',
field=models.ForeignKey(to=''myapp.Bar''),
),
migrations.AlterField(
model_name=''YetAnotherModel'',
name=''foo'',
field=models.ForeignKey(to=''myapp.Bar''),
),
migrations.RenameField(''AnotherModel'', ''foo'', ''bar''),
migrations.RenameField(''YetAnotherModel'', ''foo'', ''bar'')
]
Paso 4: aplicar la migración
python manage.py migrate
Hecho
PD He intentado este enfoque en Django 1.9