2012-07-13 51 views
4

我正在使用south來管理遷移,並且我已經到了一個角落。基本上,我有以下設置:如何在從一對一移動到一對多時執行數據遷移

應用1

class A(models.Model): 
    # bunch of attributes 

應用2

class B(models.Models): 
    instance_a = models.OneToOneField(A, null=True, blank=True, 
            editable=False) 

現在,我想從這個去這個:

應用1

class A(models.Model): 
    instance_b = models.ForeignKey(B, null=True, blank=True) 

應用2

class B(models.Models): 
    # other attributes 

我的主要問題是,我不能鬆動的數據。因此,基本上在遷移結束時,先前映射到對象B的所有對象A都應該保留該映射。例如,如果id爲7的對象A映射到id爲8的對象B,則在此過程結束時應保留此映射。

我試圖從模式遷移與臨時佔位符和數據遷移混合的幾件事情。然而,我總是在同一個地方,這是數據遷移執行時,我不再有以前的關係,以訪問正確的屬性。例如,B.instance_a不再可用。

我想兩件事情你的意見:

  • 首先,在這一切可行的使用正南方遷移。
  • 其次,我該如何着手。

感謝

回答

3

一段時間後,我得到了一個程序與django-south可能幫助別人最後。關鍵在南方的depends_on功能(http://south.aeracode.org/wiki/Dependencies)。我這樣做是在4個步驟:

首先

  • 模型A創建外鍵的值的佔位符。

所以模型A變爲:

class A(models.Model): 
    instance_b_placeholder = models.ForeignKey(A, null=True, blank=True) 

現在只需運行manage.py schemamigration app1 --auto

  • 創建datamigration所以我們可以複製的價值。目標是將數據複製到數據庫中,然後重命名屬性並刪除舊數據。問題manage.py datamigration app1 update_fields。我選擇保留app1的數據遷移。如果您不這樣做,只需確保它在之前的遷移之後運行即可。

這裏將datamigration編碼:

# Forwards: 

for b in orm['app2.B'].objects.filter(instance_b__isnull=False): 
     b.instance_a.instance_b_placeholder = b 
     b.instance_a.save() 

# Backwards: 

for r in orm['app1.A'].objects.filter(instance_b_placeholder__isnull=False): 
     r.instance_b_placeholder.instance_a = r 
     r.instance_b_placeholder.save() 

  • 從模型B刪除字段instance_b並確保讓移民跑在前面創建的一個後步。

型號B變爲:

class B(models.Model): 
    # etc... 

問題manage.py schemamigration app2 --auto和編輯遷移添加先前遷移到depends_on

depends_on = (
    ("app1", "<migration_number>_update_fields"), 
) 

第四步

  • 重命名佔位符。這是通過更改代碼中的名稱並編輯遷移來實現的。編輯是必要的,因爲south傾向於刪除並添加一個新列,但我們只希望它重新命名列。

  • 此遷移應該運行在最後位置,所以我使它依賴於上一個。

下面的代碼:

depends_on = (
    ("app2", "<previous_migration_here>"), 
) 

# Forwards: 

    db.rename_column('app1_a', 'instance_b_placeholder_id', 'instance_b_id') 

# Backwards: 

    db.rename_column('app1_a', 'instance_b_id', 'instance_b_placeholder_id') 

所以這是它。我不知道是否有其他方法可以做到這一點,但至少這對我有幫助。

相關問題