我的解決方案的工作原理如下。首先,將貓的模式,但將貓模式不變:
class Feline(models.Model):
objects = models.Manager()
class Cat(models.Model):
objects = models.Manager()
name = models.CharField(max_length=255)
miaow_factor = models.IntegerField()
接下來,創建和運行schemamigration(manage.py schemamigration animals --auto
),以便將Feline
模型添加到數據庫中。
接下來,創建一個datamigration,(manage.py datamigration animals cat_feline
)。在數據遷移中,添加代碼爲每個Cat創建一個Feline,以便每個創建的Feline與一個Cat共享一個ID。此外,更改新Felines的序列,以便爲所有新Felines分配大於最大當前Cat ID的ID。
class Migration(DataMigration):
def forwards(self, orm):
#create a Feline for each Cat
for c in orm['Cat'].objects.all():
f = orm['Feline']()
f.id = c.id
f.save()
if orm['Feline'].objects.count():
#if there are any Feline objects, make sure that new ids are allocated after the largest current ID
last_id = orm['Feline'].objects.latest('id').id
db.execute('alter sequence animals_feline_id_seq restart with %s;' % (last_id + 1))
def backwards(self, orm):
#no need to do anything if migrating backwards
pass
接下來,更改模型文件,以使貓從貓繼承和OneToOneField添加到目錄,這將是對貓新的主鍵:
class Feline(models.Model):
objects = models.Manager()
class Cat(Feline):
#n.b. Cat now inherits from Feline, not models.Model
objects = models.Manager()
feline = models.OneToOneField(Feline, parent_link = True)
name = models.CharField(max_length=255)
miaow_factor = models.IntegerField()
接下來,創建另一個schemamigration,在爲了將這些更改應用於數據庫。但是,不運行遷移。相反,在遷移更改代碼到Cat.id
列最後改名爲Cat.feline_id
class Migration(SchemaMigration):
def forwards(self, orm):
#original changes generated by South:
# Deleting field 'Cat.id'
#db.delete_column(u'animals_cat', u'id')
# Adding field 'Cat.feline'
#db.add_column(u'animals_cat', 'feline',
# self.gf('django.db.models.fields.related.OneToOneField')(default=None, to=orm['animals.Feline'], unique=True, primary_key=True),
# keep_default=False)
#instead of doing the above, just rename Cat.id to Cat.feline_id
#and drop the default numbering sequence for the Cat.feline_id field
db.rename_column('animals_cat', 'id', 'feline_id')
db.execute("ALTER TABLE animals_cat ALTER COLUMN feline_id DROP DEFAULT")
def backwards(self, orm):
#original changes generated by South:
# Adding field 'Cat.id'
#db.add_column('animals_cat', u'id',
# self.gf('django.db.models.fields.AutoField')(default=None, primary_key=True),
# keep_default=False)
# Deleting field 'Cat.feline_id'
#db.delete_column(u'animals_cat', 'feline_id')
#instead of doing the above, rename Cat.feline_id to Cat.id
#and reinstate the default numbering sequence for the Cat.id field
db.rename_column('animals_cat', 'feline_id', 'id')
db.execute("ALTER TABLE animals_cat ALTER COLUMN id SET DEFAULT nextval('u'animals_cat_id_seq'::regclass)")
if orm['Cat'].objects.count():
#if there are any Cat objects, make sure that new ids are allocated after the largest current ID
last_id = orm['Cat'].objects.latest('id').id
db.execute('alter sequence animals_cat_id_seq restart with %s;' % (last_id + 1))
,運行你剛纔編輯的schemamigration,就大功告成了。
現在,如果您願意,可以使用進一步的模式遷移和數據遷移,輕鬆地將某些字段(例如名稱)從Cat移動到Feline。
如果您想爲多個現有模型創建一個超類,那麼幸運的是我不需要處理更多的挑戰 - 在這種情況下,您可能無法爲所有實例保留相同的ID,因爲兩個不同子類中的一些實例可能會在ID上發生衝突。任何關於如何解決這個問題的想法都是值得歡迎的。
我想我會轉儲數據庫,使模型更改,遷移,然後恢復(我去的時候添加cat_id到貓表)。但那只是我。我認爲這需要一個小時,而不是幾天。 –
當然,但如果你希望你的遷移能夠在數據庫的不同實例(例如dev,live)上可重複地前後移動,那麼這並沒有什麼用處 – jcdude