South migration for multi-table inheritance

三世轮回 提交于 2019-12-21 13:01:05

问题


I have a two models that previously inherited from models.Model and now I've refactored them to inherit from the same base model. Django is using multi-table inheritance for this and I'm trying to generate a schema and data migration for this. There is existing data in the database which needs to be migrated.

I know that Django creates a OneToOneField, but I don't understand how it affects existing items in the database.

Before Inheritance

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

class AudioFile(models.Model):
    file = models.FileField()
    published_on = models.DateTimeField()

After inheritance

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

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

class AudioFile(Published):
    file = models.FileField()

Migration

This was basically the migration that was generated when I ran:

./manage.py schemamigration app --auto.

Generated file:

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)

When I try to run it, it raises an IntegrityError:

column "published_ptr_id" contains null values

回答1:


You're going to need to break that into three migrations:

  1. Schemamigration to create the app_published table, and add your two new published_ptr columns. Add these new columns with null=True instead of with 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)
    
  2. Datamigration to iterate over your existing audiofiles and blogposts. The code is basically:

    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()
    
  3. Schemamigration to remove the (now unused) id and published_on columns from your old models. Also, change published_ptr from null=True to primary_key=True on the old models.

    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'])
    


来源:https://stackoverflow.com/questions/12611427/south-migration-for-multi-table-inheritance

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!