2011-05-19 38 views
13

看起來像這樣應該是「容易」或至少記錄在某個地方,我只是無法找到它。將「through」表添加到django字段並使用South遷移?

可以說我有一個模型:

class A(models.Model): 
    users = models.ManyToMany('auth.User', blank=True) 

現在我想遷移到有一個through表字段添加到多對多關係...

class AUsers(models.Model): 
    user = models.ForeignKey('auth.User') 
    a = models.ForeignKey('A') 
    new_field = models.BooleanField() 

class A(models.Model): 
    users = models.ManyToMany('auth.User', blank=True, through='AUsers') 

然後我做的:

% ./manage.py schemamigration app --auto 

不是完全令人驚訝,它告訴我它將放棄原來的自動創建通過表格創建一個新的AUsers。現在最好的做法是什麼?是否有體面的方式遷移到新的through表中?我在Meta中使用db_table嗎?我只是沒有立即使用through=... ...然後做一個schemamigration --auto,然後datamigration複製當前表(不知何故,不知道...),然後添加through關係,讓它殺死表?

這裏有什麼竅門?這真的很難嗎?

回答

14

你應該可以很容易地做到這一點。

首先,確保您正在創建的手動通過表在數據庫中具有與最初自動創建的一個Django相同的表名稱。

因此,首先,讓我們來你改變之前考慮通過模型手冊:

class AUsers(models.Model): 
    user = models.ForeignKey('auth.User') 
    a = models.ForeignKey('A') 

    class Meta: 
     db_table = 'appname_a_user' 

ManyToManyField您使用的應該是功能性(幾乎)一樣有。其實,你可能進行一個空遷移並應用它,然後使用--auto進行更改(但不要)。

現在,像上面的示例代碼中那樣添加您的字段,然後運行./manage.py schemamigration appname manual_through_table --empty。這會給你一個名爲####_manual_through_table.py的空遷移。

在遷移本身,將會有一個forwardsbackwards方法。每一個都需要成爲一條線:

def forwards(self, orm): 
    db.add_column('appname_a_user', 'new_field', self.gf('django.db.models.fields.BooleanField')(default=False)) 

def backwards(self, orm): 
    db.delete_column('appname_a_user', 'new_field') 

這應該讓你得到你想要的。

+0

是的,我有點想知道這是否需要手動遷移。看起來,既然你也這樣想......那是對的。 db_table也是我想我也必須要做的。只是看起來像只是因爲它的遷移歷史而不存在的「殘餘」,但我想這就是我要做的。我會標記接受,如果/當它的工作。 – dlamotte 2011-05-19 20:24:08

+1

您還需要添加unique_constraint以使遷移「完成」。我覺得這有點太複雜了......至少比它需要的更多?我會把這個開放幾天,看看有人有更好的解決方案...我想看到一個...也許我需要破解南加入未來? – dlamotte 2011-05-19 20:55:26

+0

@dlamotte我自己也會遇到同樣的情況。你可以(現在,我不知道那時候)使用'db.rename_table'將表名改爲任何你想要的。 – antitoxic 2015-07-07 15:19:34

0

正如註釋提到的,第一步驟可以使用db.rename_table如上所述here,這給該通模型被簡化:

class AUsers(models.Model): 
user = models.ForeignKey('auth.User') 
a = models.ForeignKey('A') 

class Meta: 
    unique_together = (('user', 'a'),) 

然後,創建與--auto遷移(這樣你會有數據庫表中可見)的名稱,並將其替換內容:

class Migration(SchemaMigration): 

    def forwards(self, orm): 
     db.rename_table('appname_a_user', 'appname_auser') 

    def backwards(self, orm): 
     db.rename_table('appname_auser','appname_a_user') 

我剛剛應用在我的項目沒有問題。

3

如果有人遇到試着用現代人遷移框架同樣的事情時這個問題,這裏的步驟:

  1. 創建一個完全匹配內置通過表
  2. 一個新的模型類
  3. 使用Meta類將表名設置爲與現有表匹配
  4. 生成遷移,該遷移將創建新表並將其設置爲字段的貫通。
  5. 如果不運行該遷移,請編輯它以將其包裝在migrations. SeparateDatabaseAndState遷移中,其中自動生成的步驟位於state_operations字段中,並且數據庫操作爲空。
  6. 根據需要修改您的表格,確保正常生成新的遷移。