Pregunta

Estoy pensando en cambiar el nombre de varios de los modelos existentes en un proyecto de Django donde hay muchos otros modelos de relaciones de clave externa a los modelos que me gustaría cambiar el nombre.Estoy bastante seguro de que esto va a requerir de múltiples migraciones, pero no estoy seguro de que el procedimiento exacto.

Digamos que empiezo con los siguientes modelos dentro de una aplicación de Django llamado 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 de la Foo modelo debido a que el nombre en realidad no tiene sentido y está causando confusión en el código, y Bar sería un mejor nombre.

Por lo que he leído en el Django de desarrollo de la documentación, estoy suponiendo que 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()

Nota la AnotherModel nombre de campo para foo no cambia, pero la relación se actualiza a la Bar modelo.Mi razonamiento es que yo no debería cambiar demasiado de una vez, y que si he cambiado este nombre de campo para bar Yo correría el riesgo de perder los datos de esa columna.

Paso 2

Crear un vacío de la migración:

python manage.py makemigrations --empty myapp

Paso 3

Editar el Migration clase en el archivo de migración creado en el paso 2 para agregar el RenameModel la 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

Editar las relacionadas con los nombres de campo 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 otro vacío de la migración:

python manage.py makemigrations --empty myapp

Paso 7

Editar el Migration clase en el archivo de migración creado en el paso 6 para agregar el RenameField operación de la(s) por cualquier campo relacionado con los nombres de 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 2ª migración:

python manage.py migrate

Aparte de la actualización del resto del código (vistas, formularios, etc.) para reflejar los nuevos nombres de las variables, es esta, básicamente, de cómo la nueva funcionalidad de migración iba a funcionar?

También, esto parece como un montón de pasos.Puede la migración de las operaciones de ser condensada en alguna manera?

Gracias!

¿Fue útil?

Solución

Así que cuando he intentado esto, parece que se puede condensar Paso 3 - 7:

class Migration(migrations.Migration):

    dependencies = [
        ('myapp', '0001_initial'), 
    ]

    operations = [
        migrations.RenameModel('Foo', 'Bar'),
        migrations.RenameField('AnotherModel', 'foo', 'bar'),
        migrations.RenameField('YetAnotherModel', 'foo', 'bar')
    ]

Usted puede obtener algunos errores si no actualización de los nombres de donde es importado por ejemplo,admin.py y aún mayores que los archivos de migración (!).

Actualización:Como ceasaro menciona, las nuevas versiones de Django son generalmente capaces de detectar y preguntar si un modelo se cambia el nombre.Así que trate de manage.py makemigrations primero y, a continuación, compruebe el archivo de migración.

Otros consejos

Al principio, pensé que el billete de cinco libras del método ha funcionado para mí debido a que la migración ha funcionado bien hasta el paso 4.Sin embargo, el implícito de cambios " ForeignKeyField(Foo)' en 'ForeignKeyField(Bar)' no estaba relacionado de alguna de las migraciones.Esta es la razón por la migración de error cuando quise cambiar el nombre de los campos de relaciones (paso 5-8).Esto podría ser debido al hecho de que mi AnotherModel' y 'YetAnotherModel' son despachados en otras aplicaciones, en mi caso.

Así que me las arreglé para cambiar el nombre de mis modelos y campos de relaciones de hacer siguiendo los pasos siguientes:

He adaptado el método de este y en particular el truco de otranzer.

Así como el billete de cinco libras supongamos 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:

Transformar cada OneToOneField(Foo) o ForeignKeyField(Foo) en IntegerField().(Esto evitará que el id de relacionados con Foo objeto como valor de la integerfield).

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 paso 2-4 del billete de cinco libras)

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)

Crear un vacío de la migración:

python manage.py makemigrations --empty myapp

Luego editarlo como:

class Migration(migrations.Migration):

    dependencies = [
        ('myapp', '0001_initial'),
    ]

    operations = [
        migrations.RenameModel('Foo', 'Bar')
    ]

Finalmente

python manage.py migrate

Paso 3:

Transformar la Espalda de su IntegerField() en su anterior ForeignKeyField o OneToOneField pero con la nueva Barra de Modelo.(El anterior integerfield se almacena el id, por lo que django entender que y restablecer 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()

Luego de hacer:

python manage.py makemigrations 

Muy importante, en este paso se tiene que modificar cada una de las nuevas migraciones y añadir la dependencia de la RenameModel Foo-> Barra de migraciones.Por lo que si ambos AnotherModel y YetAnotherModel están en myotherapp la creación de la migración en myotherapp debe tener este aspecto:

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

Paso 4:

Finalmente, usted puede cambiar el nombre de los 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, a continuación, hacer automático el cambio de nombre

python manage.py makemigrations

(django debe preguntarle si usted realmente cambió el nombre del nombre del modelo, decir que sí)

python manage.py migrate

Y eso es todo!

Esto funciona en Django1.8

Necesitaba hacer la misma cosa.He cambiado el modelo de todos a la vez (es decir, el paso 1 y el paso 5 juntos).A continuación, se crea un esquema de migración, pero editado ser este:

class Migration(SchemaMigration):
    def forwards(self, orm):
        db.rename_table('Foo','Bar')

    def backwards(self, orm):
        db.rename_table('Bar','Foo')

Esto funcionó a la perfección.Todos los datos mostraron, todas las otras tablas de referencia de la Barra de multa.

a partir de aquí: https://hanmir.wordpress.com/2012/08/30/rename-model-django-south-migration/

Para Django 1.10, me las arreglé para cambiar el modelo de dos nombres de clase (incluyendo un ForeignKey, y con los datos) simplemente ejecutando Makemigrations y, a continuación, Migrar de la aplicación.Para el Makemigrations paso, tuve que confirmar que quería cambiar los nombres de la tabla.Migrar cambiado los nombres de las tablas sin problemas.

Luego he cambiado el nombre del campo ForeignKey a partido, y de nuevo se le preguntó por Makemigrations para confirmar que quería cambiar el nombre.Migrar de hecho el cambio.

Así que me tomé esto en dos pasos sin ningún tipo especial de archivo de edición.Me dio errores al principio porque se me olvidó cambiar el admin.py archivo, como se ha mencionado por @wasibigeek.

Yo también enfrentan el problema como v. thorey se describe y se encontró con que su enfoque es muy útil, pero puede ser condensada en menos pasos que son en realidad el paso de 5 a 8 como el billete de cinco libras describe sin paso de 1 a 4, excepto que el paso 7 necesita ser cambiado como mi siguiente paso 3.Los pasos generales son como sigue:

Paso 1:Editar las relacionadas con los nombres de campo 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:Crear un vacío de migración

python manage.py makemigrations --empty myapp

Paso 3:Editar la Migración de la clase 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

P. S.He probado este método en Django 1.9

Estoy usando Django versión 1.9.4

Tengo que seguir los siguientes pasos:-

Acabo de cambiar el nombre de la modelo oldName NewName Ejecutar python manage.py makemigrations.Se le pedirá Did you rename the appname.oldName model to NewName? [y/N] seleccionar Y

Ejecutar python manage.py migrate y se le pedirá

Los siguientes tipos de contenido están obsoletos y deben ser eliminados:

appname | oldName
appname | NewName

Los objetos relacionados con estos tipos de contenidos mediante una clave externa también ser eliminado.Estás seguro de que desea eliminar estos tipos de contenido?Si usted no está seguro, responda "no".

Type 'yes' to continue, or 'no' to cancel: Select No

Es cambiar el nombre y migrar todos los datos existentes a la nueva tabla con nombre para mí.

Por desgracia, me encontré con problemas (cada django 1.x) con cambiar el nombre de la migración que abandonar los viejos nombres de tabla en la base de datos.

Django no intentar nada en la mesa de edad, acaba de cambiar el nombre de su propio modelo.El mismo problema con las claves externas, y los índices en general los cambios no son controlados adecuadamente por Django.

La solución más simple (solución):

class Foo(models.Model):
     name = models.CharField(unique=True, max_length=32)
     ...
Bar = Foo  # and use Bar only

La solución real (una manera fácil de cambiar todos los índices, restricciones, disparadores, nombres, etc, en la 2 se compromete, sino más bien para más pequeños las tablas):

cometer Un:

  1. crear la mismo modelo como el antiguo
# deprecated - TODO: TO BE REMOVED
class Foo(model.Model):
    ...

class Bar(model.Model):
    ...
  1. interruptor de código para trabajar con el nuevo modelo Bar sólo.(incluyendo todas las relaciones en el esquema)

En la migración de preparar RunPython, que copia los datos de Foo Bar (incluyendo id de Foo)

  1. opcional optimización (si es necesario para la mayor de las tablas)

cometer B: (no hay prisa, hazlo cuando todo un equipo de migrar)

  1. la entrega segura de que el viejo modelo Foo

además de la limpieza:

  • la calabaza de las migraciones

error en Django:

Necesitaba cambiar el nombre de un par de tablas.Pero sólo un modelo cambie el nombre fue notado por Django.Eso pasó porque Django recorre añadido, a continuación, quita los modelos.Para cada par comprueba si son de la misma aplicación y se han campos idénticos.Sólo una mesa no tenía las claves externas de las tablas se ha cambiado el nombre (claves foráneas contener nombre de clase del modelo, como lo recuerde).En otras palabras, sólo uno de la tabla, no se cambia de campo.Por eso se ha notado.

Así, la solución es cambiar el nombre de una tabla en un momento, el cambio de modelo nombre de la clase en models.py, posiblemente views.py, y hacer una migración.Después de inspeccionar el código para otras referencias (modelo nombres de la clase, relacionados con (consulta) los nombres, los nombres de las variables).Hacer una migración, si es necesario.A continuación, opcionalmente se combinan todos estos migraciones en uno (asegúrese de copiar las importaciones así).

Me gustaría hacer @ceasaro palabras, la mía en su comentario sobre este respuesta.

Las nuevas versiones de Django puede detectar cambios y preguntar acerca de lo que se hizo.También me gustaría añadir que Django puede mezclar el orden de ejecución de algunos comandos de migración.

Sería conveniente aplicar pequeños cambios y ejecutar makemigrations y migrate y si el error se produce la migración de archivo puede ser editado.

Algunas de las líneas de orden de ejecución puede ser cambiado para evitar errores.

Sólo quería confirmar y añadir ceasaro comentario.Django 2.0 parece hacer esto de forma automática ahora.

Estoy en Jango 2.2.1, todo lo que tenía que hacer para cambiar el nombre del modelo y ejecutar makemigrations.

Aquí se pregunta si yo había cambiado el nombre de la clase específica de la a a la B, yo elegí sí y corrió a migrar y todo parece funcionar.

Nota: yo no cambie el nombre de la modelo antiguo nombre en todos los archivos dentro del proyecto/migraciones carpeta.

Si usted está usando un buen IDE como PyCharm usted puede hacer clic derecho en el nombre del modelo y hacer un refactorizar -> cambiar nombre.Esto le ahorra la molestia de ir a través de todo el código que hace referencia a la modelo.A continuación, ejecute makemigrations y migrar.Django 2+ simplemente confirmar el cambio de nombre.

He actualizado a Django a partir de la versión 10 a la versión 11:

sudo pip install -U Django

(-U para "actualizar") y se solucionó el problema.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top