6

以前に models.Model から継承した 2 つのモデルがあり、同じ基本モデルから継承するようにリファクタリングしました。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()

継承後

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

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

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

移行

これは基本的に、実行時に生成された移行です。

./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)

実行しようとすると、IntegrityError が発生します。

column "published_ptr_id" contains null values
4

1 に答える 1

10

これを3つの移行に分割する必要があります。

  1. スキーマ移行を使用してapp_publishedテーブルを作成し、2つの新しい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)
    
  2. 既存のオーディオファイルとブログ投稿を反復処理するためのデータ移行。コードは基本的に次のとおりです。

    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. 古いモデルから(現在は使用されていない)id列とpublished_on列を削除するためのスキーマ移行。また、古いモデルでpublished_ptrをからに変更しnull=Trueます。primary_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'])
    
于 2012-09-26T23:30:00.473 に答える