2010-05-19 61 views
138

我一直在尋找南方網站,谷歌和SO的答案,但找不到一個簡單的方法來做到這一點。使用Django/South重命名模型的最簡單方法是什麼?

我想使用South重命名一個Django模型。 假設你有以下幾點:

class Foo(models.Model): 
    name = models.CharField() 

class FooTwo(models.Model): 
    name = models.CharField() 
    foo = models.ForeignKey(Foo) 

,並要轉換美孚吧,即

class Bar(models.Model): 
    name = models.CharField() 

class FooTwo(models.Model): 
    name = models.CharField() 
    foo = models.ForeignKey(Bar) 

爲了保持它的簡單,我只是想將名稱從Foo更改爲Bar,但現在請忽略FooTwo中的foo成員。

使用South進行此操作的最簡單方法是什麼?

  1. 我可以做一個數據遷移,但這似乎很相關。
  2. 編寫自定義遷移,例如db.rename_table('city_citystate', 'geo_citystate'),但我不確定如何解決這種情況下的外鍵。
  3. 一個更簡單的方法,你知道嗎?
+4

另請參閱http://stackoverflow.com/questions/3235995/django-how-to-rename-a-model-field-using-south用於重命名*模型字段*而不是*模型*。 – 2011-09-29 04:31:52

+0

爲Django> = 1.8優化的解決方案http://stackoverflow.com/questions/25091130/django-migration-strategy-for-renaming-a-model-and-relationship-fields – 2016-03-17 01:56:46

回答

128

要回答你的第一個問題,簡單的模型/表重命名是非常簡單的。運行命令:

./manage.py schemamigration yourapp rename_foo_to_bar --empty 

(更新2:嘗試--auto而不是--empty避免低於警告感謝@KFB的提示)

如果您使用南方的舊版本,您需要startmigration而不是schemamigration

,然後手動編輯遷移文件看起來像這樣:

class Migration(SchemaMigration): 

    def forwards(self, orm): 
     db.rename_table('yourapp_foo', 'yourapp_bar') 


    def backwards(self, orm): 
     db.rename_table('yourapp_bar','yourapp_foo') 

您可以在此更簡單地使用你的模型類的db_table元選項完成。但是每次你這樣做的時候,你都會增加代碼庫的遺留重量 - 類名與表名不一致會使你的代碼難以理解和維護。爲了清楚起見,我完全支持這樣的簡單重構。

(更新)我剛剛在生產中試過這個,當我申請遷移時遇到了一個奇怪的警告。它說:

The following content types are stale and need to be deleted: 

    yourapp | foo 

Any objects related to these content types by a foreign key will also 
be deleted. Are you sure you want to delete these content types? 
If you're unsure, answer 'no'. 

我回答「不」,一切似乎都很好。

+0

當我這樣做時,我失去了foo中的所有行。我究竟做錯了什麼? – jMyles 2010-11-23 08:50:05

+0

@Justin - 很難說沒有很多更多的細節。在這裏寫一個新的SO問題並鏈接到它的評論? – Leopd 2010-11-23 15:57:14

+0

這似乎破壞了依賴於'Foo'的舊遷移。 – luqui 2011-07-25 06:44:44

5

南不能自己做 - 它怎麼知道Bar代表什麼Foo用於?這是我爲自定義遷移寫的東西。您可以像上面所做的那樣在代碼中更改ForeignKey,然後這只是重命名相應字段和表格的情況,您可以按照自己的意願進行操作。

最後,你真的需要這樣做嗎?我還沒有需要重新命名模型 - 模型名稱只是一個實現細節 - 特別是考慮到verbose_name Meta選項的可用性。

+7

或者,在代碼中重命名模型,但使用'db_table' Meta選項保持數據庫表名稱相同。 – 2010-05-19 06:32:23

+0

@Daniel - 你知道'db_table'是否用於派生外鍵名? – 2010-05-19 07:40:01

+0

我相信它。如果更改模型名稱並設置db_table,則所有內容仍應按預期工作。 – 2010-05-19 10:34:25

65

請在models.py的變化,然後運行

./manage.py schemamigration --auto myapp 

當您檢查遷移文件,你會看到,它刪除表,並創建一個新的

class Migration(SchemaMigration): 

    def forwards(self, orm): 
     # Deleting model 'Foo'                              
     db.delete_table('myapp_foo') 

     # Adding model 'Bar'                               
     db.create_table('myapp_bar', (
     ... 
     )) 
     db.send_create_signal('myapp', ['Bar']) 

    def backwards(self, orm): 
     ... 

這不是完全是你想要的。相反,編輯遷移,這樣它看起來像:

class Migration(SchemaMigration): 

    def forwards(self, orm): 
     # Renaming model from 'Foo' to 'Bar'                              
     db.rename_table('myapp_foo', 'myapp_bar')                               
     if not db.dry_run: 
      orm['contenttypes.contenttype'].objects.filter(
       app_label='myapp', model='foo').update(model='bar') 

    def backwards(self, orm): 
     # Renaming model from 'Bar' to 'Foo'                              
     db.rename_table('myapp_bar', 'myapp_foo')                               
     if not db.dry_run: 
      orm['contenttypes.contenttype'].objects.filter(app_label='myapp', model='bar').update(model='foo') 

在沒有update聲明中,db.send_create_signal通話將創建一個新ContentType新型號名稱。但是,如果有數據庫對象指向它(例如,通過GenericForeignKey),最好只有updateContentType

另外,如果你已經改名爲某些列其中外鍵的重命名的模式,不以

db.rename_column(myapp_model, foo_id, bar_id) 
+8

+1在contenttypes表中重命名模型 – ACGray 2014-03-19 10:57:28

+2

我得到錯誤KeyError:「應用'contenttypes'的模型'contenttype'在此遷移中不可用。「另外,我有一個django_content_type表,但不是內容類型表。 (Django 1.6) – Seth 2014-04-08 19:51:33

+2

@Seth我通過在單獨的數據遷移中更新ContentType模型並通過使用「--frozen」將「contenttypes.ContentType」模型添加到凍結模型來解決此問題標誌到''./manage.py datamigration''。例如:''./manage.py datamigration - frozen contenttypes myapp update_contenttypes''。然後使用上面指定的內容類型更新代碼編輯myapp_migrations/NNNN_update_contenttypes.py。 – 2014-07-22 18:52:58

-1

我跟着上面Leopd的解決方案忘記。但是,這並沒有改變型號名稱。我在代碼中手動更改了它(也在相關模型中,這被稱爲FK)。並完成了另一次南遷,但有了 - 做出選擇。這使模型名稱和表名稱相同。

剛剛意識到,可以先更改型號名稱,然後在應用它們之前編輯遷移文件。更乾淨。

相關問題