用于多表继承的南迁移

Rud*_*lah 6 django django-models django-south

我有两个以前继承自models.Model的模型,现在我重构它们以继承相同的基本模型.Django正在为此使用多表继承,我正在尝试为此生成模式和数据迁移.数据库中存在需要迁移的现有数据.

我知道Django创建了OneToOneField,但我不明白它如何影响数据库中的现有项目.

在继承之前

class BlogPost(models.Model):
    name = models.CharField()
    published_on = models.DateTimeField()

class AudioFile(models.Model):
    file = models.FileField()
    published_on = models.DateTimeField()
Run Code Online (Sandbox Code Playgroud)

继承之后

class Published(models.Model):
    published_on = models.DateTimeField()

class BlogPost(Published):
    name = models.CharField()

class AudioFile(Published):
    file = models.FileField()
Run Code Online (Sandbox Code Playgroud)

移民

这基本上是我运行时生成的迁移:

./manage.py schemamigration app --auto.

生成的文件:

class Migration(SchemaMigration):
    def forwards(self, orm):
        db.create_table('app_published', (
            ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
            ('published_on', self.gf('django.db.models.fields.DateTimeField')()),
        ))
        db.send_create_signal('app', ['Published'])

        db.delete_column('app_blogpost', 'published_on')
        db.delete_column('app_blogpost', 'id')
        db.add_column('app_blogpost', 'published_ptr', self.gf('django.db.models.fields.related.OneToOneField')(default=None, to=orm['app.Published'], unique=True, primary_key=True), keep_default=False)

        db.delete_column('app_audiofile', 'published_on')
        db.delete_column('app_audiofile', 'id')
        db.add_column('app_audiofile', 'published_ptr', self.gf('django.db.models.fields.related.OneToOneField')(default=None, to=orm['app.Published'], unique=True, primary_key=True), keep_default=False)
Run Code Online (Sandbox Code Playgroud)

当我尝试运行它时,它会引发IntegrityError:

column "published_ptr_id" contains null values
Run Code Online (Sandbox Code Playgroud)

dok*_*ebi 10

您需要将其分解为三次迁移:

  1. Schemamigration用于创建app_published表,并添加两个新的published_ptr列.添加这些新列null=True而不是primary_key=True:

    db.create_table('app_published', (
        ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
        ('published_on', self.gf('django.db.models.fields.DateTimeField')()),
    ))
    db.add_column('app_blogpost', 'published_ptr', self.gf('django.db.models.fields.related.OneToOneField')(default=None, to=orm['app.Published'], null=True), keep_default=False)
    db.add_column('app_audiofile', 'published_ptr', self.gf('django.db.models.fields.related.OneToOneField')(default=None, to=orm['app.Published'], null=True), keep_default=False)
    
    Run Code Online (Sandbox Code Playgroud)
  2. Datamigration将遍历您现有的audiofiles和blogposts.代码基本上是:

    for blogpost in orm.BlogPost.objects.all():
        published = orm.Published.objects.create(published_on=blogpost.published_on)
        blogpost.published_ptr = published
        blogpost.save()
    
    for audiofile in orm.AudioFile.objects.all():
        published = orm.Published.objects.create(published_on=audiofile.published_on)
        audiofile.published_ptr = published
        audiofile.save()
    
    Run Code Online (Sandbox Code Playgroud)
  3. Schemamigration从旧模型中删除(现在未使用的)id和published_on列.此外,从published_ptr改变null=Trueprimary_key=True对老款.

    db.delete_column('app_blogpost', 'published_on')
    db.delete_column('app_blogpost', 'id')
    db.delete_column('app_audiofile', 'published_on')
    db.delete_column('app_audiofile', 'id')
    
    db.alter_column('app_blogpost', 'published_ptr', self.gf('django.db.models.fields.related.OneToOneField')(default=None, to=orm['app.Published'], null=False))
    db.alter_column('app_audiofile', 'published_ptr', self.gf('django.db.models.fields.related.OneToOneField')(default=None, to=orm['app.Published'], null=False))
    
    db.create_index('app_blogpost', ['published_ptr'], unique=True)
    db.create_index('app_audiofile', ['published_ptr'], unique=True)
    db.create_primary_key('app_blogpost', ['published_ptr'])
    db.create_primary_key('app_audiofile', ['published_ptr'])
    
    Run Code Online (Sandbox Code Playgroud)