Мое решение работает следующим образом. Сначала добавьте модель Feline, но оставьте модель Cat без изменений:
class Feline(models.Model):
objects = models.Manager()
class Cat(models.Model):
objects = models.Manager()
name = models.CharField(max_length=255)
miaow_factor = models.IntegerField()
Затем создайте и запустите миграцию схемы (manage.py schemamigration animals --auto
), чтобы добавить модель Feline
в базу данных.
Затем создайте перенос данных (manage.py datamigration animals cat_feline
). В миграции данных добавьте код для создания кошачьих для каждой кошки, чтобы каждая созданная кошка имела общий идентификатор с кошкой. Кроме того, измените последовательность для новых животных из семейства кошачьих, чтобы всем новым животным из семейства кошачьих назначались идентификаторы, превышающие самый большой текущий идентификатор кошки.
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
Затем измените файл моделей, чтобы Cat унаследовал от Feline, и добавьте OneToOneField в Cat, который будет новым первичным ключом для Cats:
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()
Затем создайте еще одну миграцию схемы, чтобы применить эти изменения к базе данных. Однако не выполняйте перенос. Вместо этого измените код в миграции, чтобы переименовать столбец 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))
Наконец, запустите только что отредактированную схему миграции, и все готово.
Теперь, если вы хотите, вы можете легко переместить некоторые поля (например, имя) из Cat в Feline, используя дальнейшие схемы и миграции данных.
Еще одна проблема (с которой мне, к счастью, не приходилось сталкиваться) будет, если вы захотите создать суперкласс для нескольких существующих моделей - в этом случае вы не сможете сохранить один и тот же идентификатор для всех экземпляров, как некоторые экземпляры в два разных подкласса могут конфликтовать по идентификатору. Приветствуются любые мысли о том, как обойти это.
person
jcdude
schedule
22.01.2014