2011-09-07 10 views
16

Sto utilizzando South con la mia app Django. Ho due modelli che sto cambiando dall'avere una relazione ForeignKey con una relazione OneToOneField. Quando ho eseguito questa migrazione sul mio database di sviluppo, è andato tutto bene. Quando le migrazioni vengono eseguite come parte della creazione di un database di test, la migrazione più recente non riesce con un errore 1005 MySQL: "Impossibile creare table mydb. # Sql-3249_1d (errno: 121)". Fare un po 'su Google ha rivelato che questo è solitamente un problema con il tentativo di aggiungere un vincolo con lo stesso nome di un vincolo esistente. La riga specifica nella migrazione che questo non si verifica è:Django - Modifica una relazione ForeignKey con OneToOne

Il rapporto è stato modificato da:

class MyModel(models.Model): 
    othermodel = models.ForeignKey(OtherModel) 

a

class MyModel(models.Model): 
    othermodel = models.OneToOneField(OtherModel) 

che ha generato le seguenti istruzioni nella migrazione:

db.alter_column('myapp_mymodel', 'othermodel_id', self.gf('django.db.models.fields.related.OneToOneField')(to=orm['myapp.OtherModel'], unique=True)) 

db.create_unique('myapp_mymodel', ['othermodel_id']) 

Ma invece di non riuscire sulla chiamata create_unique, non funziona sullo 01 Chiamata. Ho eseguito il seguente comando per vedere quali SQL è stato generato:

python manage.py migrate myapp 0010 --db-dry-run --verbosity=2 

e stampato fuori

myapp:0010_auto__chg_field_mymodel_othermodel__add_unique_mymodel 
    = ALTER TABLE `myapp_mymodel` ADD CONSTRAINT `myapp_mymodel_othermodel_id_uniq` UNIQUE (`othermodel_id`) [] 
    = SET FOREIGN_KEY_CHECKS=1; [] 
    = ALTER TABLE `myapp_mymodel` ADD CONSTRAINT `myapp_mymodel_othermodel_id_uniq` UNIQUE (`othermodel_id`) [] 

Sembra strano che si sta cercando di eseguire il ADD CONSTRAINT due volte, ma se mi tolgo la db.create_unique chiamata, non viene generato SQL quando lo eseguo con --db-dry-run, ma ottengo ancora l'errore se lo eseguo per davvero.

Sono in perdita qui, ogni aiuto è apprezzato.

+1

ho creato esattamente la stessa migrazione alcuni giorni fa e ha funzionato bene. Potresti provare lo stesso codice con un back-end del database diverso (l'ho fatto su un database PostgreSQL). Inoltre, controlla la versione Sud. – emyller

+0

Vorrei poterti aiutare - Ho apportato la modifica, generato lo stesso codice Python e SQL, e la migrazione è andata bene, usando mysql 5.1.56 per win32. – Hannele

+0

Chiedilo nella mailing list Sud ed è molto probabile che tu trovi la risposta. –

risposta

0

La prima cosa che proverei sarebbe aggiungere uno db.delete_unique(...) in vari punti per vedere se potrei hackerarlo.

In mancanza di questo, mi piacerebbe dividerlo in 3 migrazioni:

  1. una migrazione dello schema per aggiungere una nuova colonna per l'OnetoOne
  2. una migrazione dei dati per copiare tutti i valori FK da antica colonna verso new
  3. una migrazione dello schema per rimuovere la vecchia colonna, che poi avrei modificato manualmente per includere un comando per rinominare la nuova colonna con la stessa di quella vecchia.
11

In realtà non è necessaria alcuna migrazione. Le relazioni OneToOne e ForeignKey hanno uno schema di database compatibile sotto l'hook: una colonna semplice con l'altro ID oggetto in una tabella.

Basta falsificare la migrazione con migrate --fake se non si vuole entrare nel problema di dire a sud di ignorare questa modifica.

+0

E se sei in dubbio che @ e-satis è corretto su questo, prendi questo bocconcino dal codice ('django.db.models.fields.related'):" Un OneToOneField è essenzialmente uguale a un ForeignKey , con l'eccezione che porta sempre con sé un vincolo "unico". E notare che OneToOne eredita effettivamente da ForeignKey con solo qualche piccola modifica. – mlissner

+0

Per essere precisi, la modifica di un campo da ForeignKey a OneToOneField HA un effetto sul database (almeno su quei vincoli di supporto), che non dovrebbe essere saltato: un ForeignKey non è univoco, mentre OneToOneField lo è. In Django 1.8 - usando il comando nativo 'makemigrations' su mysql backend - non ho avuto alcun problema. La migrazione ha eliminato correttamente il precedente indice non univoco sul campo a livello di DB e ha impostato il nuovo indice univoco. – baxeico

1

Sono d'accordo con @ e-satis che l'obiettivo qui è quello di simulare una migrazione, ma suggerisco un approccio diverso se si lavora con una squadra.

Se si crea una migrazione, quindi --fake, tutti i membri del team dovranno ricordarsi di --fake. Se qualcuno di loro non fa questo quando si aggiorna, sei nei guai.

Un approccio migliore è quello di creare una migrazione vuota, poi migrarlo:

manage.py schemamigration yourapp --empty fake_migration_of_foreign_key_to_onetoone 
manage.py migrate # Like you always do!