2010-08-14 17 views
13

Cambiar el nombre de un simple etc Charfield parece fácil (Django - How to rename a model field using South?)¿Cómo cambiar el nombre de un campo de clave externa con Sur?

Sin embargo cuando intento utilizar el mismo en un campo ForeignKey consigo un error:

_mysql_exceptions.OperationalError: (1091, "Can't DROP '[new_fkey_field_name]'; check that column/key exists") 

que se deriva de la migración trata de abrir el revés por algún motivo (como se evidencia en la traza).

¿Alguna idea?

+0

Parece que hay un problema en el lado de MySql. - ¿Qué motor de almacenamiento usaste? - ¿Utiliza MyISAM (que no es compatible con la integridad referencial)? - ¿Lo intentó con sqlite de postgresql? –

+0

Pregunta similar aquí: http: // stackoverflow.com/questions/1600129/using-south-to-refactor-a-django-model-with-inheritence –

Respuesta

4

actualización : con mysql-5.5.30-1.fc18.x86_64 y

MySQL-python==1.2.4 
Django==1.4.2 
South==0.7.6 

las siguientes obras:

class Migration(SchemaMigration_: 
    def forwards(self, orm): 
     db.rename_column('app_model', 'old_id', 'new_id') 
     db.alter_column('app_model', 'new_id', 
         self.gf('django.db.models.fields.related.ForeignKey')(
          blank=True, 
          null=True, 
          to=orm['app.OtherModel'] 
         )) 

    def backwards(self, orm): 
     db.rename_column('app_model', 'new_id', 'old_id') 
     db.alter_column('app_model', 'old_id', 
         self.gf('django.db.models.fields.related.ForeignKey')(
          blank=True, 
          null=True, 
          to=orm['app.OtherModel'] 
         )) 

Como @Eloff comenta, South no puede encontrar el FK original por razones desconocidas, pero no parece importar. No hay necesidad de una migración de datos (creo) ya que los valores de pk no deberían cambiar.

La especificación de campo (usando self.gf) está tomada de las migraciones autogeneradas de South para la coherencia.

+1

Puede ser mordido por [este pequeño error del Sur] (http://south.aeracode.org/ticket/1186) si usa esta solución. Ya sea un parche de mono en el sur (ver ticket) o soborno [Andrew] (http://aeracode.org) para arreglarlo – supervacuo

6

Al cambiar el nombre de un ForeignKey, recuerde agregar _id al final del nombre del campo que utiliza en Django. P.ej.

db.rename_column('accounts_transaction', 'operator_id', 'responsible_id') 

Y no

db.rename_column('accounts_transaction', 'operator', 'responsible') 

Pero sólo he probado esto en sqlite (que en realidad no tienen la ALTER_TABLE en absoluto), por lo que no se sabe si realmente funciona en MySQL/postgres.

24

En primer lugar, debe utilizar el nombre de columna db no el del modelo. Por ejemplo: foobar_id no foobar.

Luego hay que soltar las limitaciones fk y volver a ellos después de cambio de nombre:

db.drop_foreign_key('app_model', 'old_id') 
db.rename_column('app_model', 'old_id', 'new_id') 
db.alter_column('app_model', 'new_id', models.ForeignKey(to=orm['app.OtherModel'])) 

Si su fk es anulable es necesario utilizar cambiarlo a:

db.alter_column('app_model', 'new_id', models.ForeignKey(null=True, to=orm['app.OtherModel'])) 
+1

Esto no funciona con MySQL 5.5.13 (sur 0.7.3) drop_foreign_key no encuentra la restricción de clave foránea. – Eloff

+0

¿No debería alter_column() usar 'new_id'? – del

+0

Eso es realmente difícil de depurar si el fk es nulo. Gracias hombre –

11

usuarios de MySQL debería ser conscientes de este error en el sur, si es que todavía se aplica:

http://south.aeracode.org/ticket/697

La solución consiste en realizar la migración en 3 pasos:

1) Añadir nuevo campo

2) Datos de migrar los datos a un nuevo campo

3) eliminar el campo de edad

+0

En mi humilde opinión, esta es la única solución que funciona de manera confiable con MySQL DBs –

Cuestiones relacionadas