¿La forma más fácil de cambiar el nombre de un modelo usando Django / South?

He estado buscando una respuesta a esto en el sitio de South, Google y SO, pero no pude encontrar una forma sencilla de hacerlo.

Quiero cambiar el nombre de un modelo de Django usando South. Digamos que tienes lo siguiente:

class Foo(models.Model): name = models.CharField() class FooTwo(models.Model): name = models.CharField() foo = models.ForeignKey(Foo) 

y quieres convertir Foo a Bar, concretamente

 class Bar(models.Model): name = models.CharField() class FooTwo(models.Model): name = models.CharField() foo = models.ForeignKey(Bar) 

Para mantenerlo simple, solo trato de cambiar el nombre de Foo a Bar , pero por ahora ignoro al miembro foo en FooTwo .

¿Cuál es la forma más fácil de hacer esto usando South?

  1. Probablemente podría hacer una migración de datos, pero eso parece bastante complicado.
  2. Escriba una migración personalizada, por ejemplo, db.rename_table('city_citystate', 'geo_citystate') , pero no estoy seguro de cómo corregir la clave externa en este caso.
  3. ¿Una forma más fácil de saber?

Para responder a su primera pregunta, el simple cambio de nombre de modelo / tabla es bastante sencillo. Ejecuta el comando:

 ./manage.py schemamigration yourapp rename_foo_to_bar --empty 

(Actualización 2: intente --auto lugar de --empty para evitar la siguiente advertencia. Gracias a @KFB por la sugerencia).

Si está utilizando una versión anterior de south, necesitará startmigration lugar de schemamigration .

Luego edite manualmente el archivo de migración para que se vea así:

 class Migration(SchemaMigration): def forwards(self, orm): db.rename_table('yourapp_foo', 'yourapp_bar') def backwards(self, orm): db.rename_table('yourapp_bar','yourapp_foo') 

Puede lograr esto más simplemente usando la opción db_table Meta en su clase de modelo. Pero cada vez que haces eso, aumentas el peso heredado de tu base de código: tener nombres de clases que difieren de los nombres de tablas hace que tu código sea más difícil de entender y mantener. Estoy totalmente de acuerdo con hacer refactorizaciones simples como esta por claridad.

(actualización) Acabo de probar esto en producción y recibí una advertencia extraña cuando fui a aplicar la migración. Decía:

 The following content types are stale and need to be deleted: yourapp | foo Any objects related to these content types by a foreign key will also be deleted. Are you sure you want to delete these content types? If you're unsure, answer 'no'. 

Respondí “no” y todo parecía estar bien.

Haz los cambios en models.py y luego ejecuta

 ./manage.py schemamigration --auto myapp 

Cuando inspeccione el archivo de migración, verá que elimina una tabla y crea una nueva

 class Migration(SchemaMigration): def forwards(self, orm): # Deleting model 'Foo' db.delete_table('myapp_foo') # Adding model 'Bar' db.create_table('myapp_bar', ( ... )) db.send_create_signal('myapp', ['Bar']) def backwards(self, orm): ... 

Esto no es exactamente lo que quieres. En su lugar, edite la migración para que se vea como:

 class Migration(SchemaMigration): def forwards(self, orm): # Renaming model from 'Foo' to 'Bar' db.rename_table('myapp_foo', 'myapp_bar') if not db.dry_run: orm['contenttypes.contenttype'].objects.filter( app_label='myapp', model='foo').update(model='bar') def backwards(self, orm): # Renaming model from 'Bar' to 'Foo' db.rename_table('myapp_bar', 'myapp_foo') if not db.dry_run: orm['contenttypes.contenttype'].objects.filter(app_label='myapp', model='bar').update(model='foo') 

En ausencia de la instrucción de update , la llamada db.send_create_signal creará un nuevo ContentType con el nuevo nombre del modelo. Pero es mejor simplemente update el ContentType que ya tiene en caso de que haya objetos en la base de datos que lo apunten (por ejemplo, a través de un GenericForeignKey ).

Además, si ha cambiado el nombre de algunas columnas que son claves externas al modelo cuyo nombre ha cambiado, no olvide

 db.rename_column(myapp_model, foo_id, bar_id) 

South no puede hacerlo por sí mismo. ¿Cómo sabe que Bar representa lo que Foo solía hacer? Este es el tipo de cosas para las que escribiría una migración personalizada. Puede cambiar su ForeignKey en el código como lo ha hecho anteriormente, y luego solo tiene que cambiar el nombre de los campos y las tablas correspondientes, lo que puede hacer de la manera que desee.

Finalmente, ¿realmente necesitas hacer esto? Todavía no necesito cambiar el nombre de los modelos: los nombres de los modelos son solo un detalle de la implementación, especialmente dada la disponibilidad de la opción verbose_name Meta.

Seguí la solución de Leopd arriba. Pero, eso no cambió los nombres de los modelos. Lo cambié manualmente en el código (también en modelos relacionados donde se conoce como FK). Y hecho otra migración al sur, pero con opción –fake. Esto hace que los nombres de los modelos y los nombres de tablas sean iguales.

Acabo de darse cuenta, uno podría comenzar por cambiar los nombres de los modelos, luego editar el archivo de migraciones antes de aplicarlos. Mucho más limpio.