2011-09-07 105 views
16

我正在使用South和我的Django應用程序。我有兩個模型,我從ForeignKey關係變爲OneToOneField關係。當我在我的開發數據庫上運行這個遷移時,它運行良好。當遷移作爲創建測試數據庫的一部分運行時,最新的遷移失敗並出現MySQL 1005錯誤:「無法創建表mydb。#sql-3249_1d(errno:121)」。做一些谷歌搜索顯示,這通常是一個問題,試圖添加與現有約束相同的名稱的約束。在遷移它未能對特定行是:Django - 將OneKey關係更改爲OneToOne

的關係變爲從:

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

class MyModel(models.Model): 
    othermodel = models.OneToOneField(OtherModel) 
,其產生在遷移以下語句

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']) 

但不是在create_unique呼叫失敗,它是失敗的01致電。我跑到下面的命令來查看正在發生什麼SQL:

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

,並打印出來

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`) [] 

似乎很奇怪,它正試圖運行ADD CONSTRAINT兩次,但如果我刪除db.create_unique調用,當我使用--db-dry-run運行時,不生成SQL,但如果我真的運行它,仍然會出現錯誤。

我在這裏虧本,任何幫助表示讚賞。

+1

我創建完全相同的遷移一些天前,它運行得很好。你可以用不同的數據庫後端嘗試相同的代碼(我在PostgreSQL數據庫中做過)。 另外,請檢查您的南方版本。 – emyller

+0

希望我能幫忙 - 我做了改變,它生成了相同的python和SQL代碼,並且遷移運行得很好,使用mysql 5.1.56 for win32。 – Hannele

+0

在South郵件列表上詢問這個問題,你很可能找到答案。 –

回答

0

我想嘗試的第一件事就是在各個地方添加一個db.delete_unique(...)以查看我是否可以破解它。

做不到這一點,我把它分解成3遷移:

  1. 模式遷移到添加新列的OneToOne
  2. 數據遷移從舊列到複製所有FK值新
  3. 模式遷移刪除舊的列,然後我會手動編輯,包括一個命令重新命名新列與舊的列相同。
11

實際上根本不需要遷移。 OneToOne和ForeignKey關係在鉤子下有一個兼容的數據庫模式:一個簡單的列,另一個對象ID在一個表中。

假如你不想讓南方人忽視這種變化,那麼只需假冒移民migrate --fake即可。

+0

如果您完全懷疑@ e-satis是否正確,請從代碼('django.db.models.fields.related')中獲取這些資訊:「OneToOneField基本上與ForeignKey相同,除了它總是帶有一個「唯一」約束「並且注意OneToOne實際上只是從ForeignKey繼承而來,只做了一些小的調整。 – mlissner

+0

準確地說,將字段從ForeignKey更改爲OneToOneField對數據庫(至少在那些支持約束的情況下)有影響,不應該跳過:ForeignKey不唯一,而OneToOneField是。在Django 1.8中 - 在mysql後端使用本地命令'makemigrations' - 我沒有任何問題。遷移正確刪除了數據庫級別字段中以前的非唯一索引,並設置了新的唯一索引。 – baxeico

1

我同意@ e-satis這裏的目標是僞造一個遷移,但是如果你和一個團隊一起工作,我建議採用不同的方法。

如果你創建一個遷移然後--fake它,你所有的團隊成員也需要記住--fake它。如果他們中的任何一個在升級時都沒有這樣做,那就麻煩了。

更好的方法是創建一個空的遷移,然後遷移它:

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