1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Python(Django) x AWS 一人アドベントカレンダーAdvent Calendar 2024

Day 21

【Django】テーブル作成と初期データ挿入を一回のmigrateで実施する方法

Posted at

概要

Djangoにて、マイグレーションファイルでテーブルを作成すると同時に、初期データも挿入したい場合がありますよね。外部キー制約を使っていてnullが許容されていないケースなど。

今回、マイグレーションファイルとfixturesを利用して実装できたので、その手順を紹介します。

手順

以下のようなモデルがあるとします。

book/models.py
from django.db import models

class Author(models.Model):
    author_id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=255, null=True)

    class Meta:
        db_table = 'author'

class Book(models.Model):
    book_id = models.AutoField(primary_key=True)
    title = models.CharField(max_length=255, null=True)
    # author_id = models.ForeignKey('Author', on_delete=models.CASCADE, null=False, db_column='author_id')

    class Meta:
        db_table = 'book'

ここで、Bookモデルのauthor_idは外部キー制約を利用しており、null=Falseです。このままコメントアウトを外して実行すると、authorテーブルにまだレコードがないので外部キー制約違反でエラーになってしまいます。

ということで、以下の順序で実施します。

authorテーブルとbookテーブル(author_idなし)の作成を行うマイグレーション生成
②初期データ用のJSONを作成
authorテーブルにレコードを追加するマイグレーション生成
bookテーブルにauthor_id(外部キー)を追加するマイグレーション生成
⑤マイグレート実施

authorテーブルとbookテーブル(author_idなし)の作成を行うマイグレーション生成

上記のmodels.pyで一度python manage.py makemigrationsを実施してマイグレーションファイルを作成。

1つ目であれば0001_initialと言う名前になります。

②初期データ用のJSONを作成

次に挿入データ用のJSONを作成し、fixturesディレクトリ以下におきます。

book/fixtures/author_initial_data.json
[
    {
        "model": "app_name.author",
        "pk": 1,
        "fields": {
            "name": "Taro Yamada"
        }
    },
    {
        "model": "app_name.author",
        "pk": 2,
        "fields": {
            "name": "Jiro Tanaka"
        }
    }
]

authorテーブルにレコードを追加するマイグレーション生成

0002_load_author_data.pyと言うファイルをmigrationsディレクトリ以下に作成して、以下の内容を書きます。ここでは、先ほど作成したfixturesを実行するコマンドを書いています。

book/migrations/0002_load_author_data.py
from django.core.management import call_command
from django.db import migrations

def load_fixture(apps, schema_editor):
    call_command('loaddata', 'fixtures/author_initial_data.json', app_label='book')

class Migration(migrations.Migration):

    dependencies = [
        ('book', '0001_initial'),
    ]

    operations = [
        migrations.RunPython(load_fixture),
    ]

上記ではcall_command関数を使用して、Djangoのloaddataコマンドを呼び出しています。
loaddataコマンドは、指定されたJSONファイルからデータを読み込み、DBに挿入してくれます。

bookテーブルにauthor_id(外部キー)を追加するマイグレーション生成

最後に、Bookモデルの外部キーのコメントアウト(author_id...)を外し、再びpython manage.py makemigrationsを実施してマイグレーションファイルを作成します。

book/models.py
from django.db import models

class Author(models.Model):
    author_id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=255, null=True)

    class Meta:
        db_table = 'author'

class Book(models.Model):
    book_id = models.AutoField(primary_key=True)
    title = models.CharField(max_length=255, null=True)
    author_id = models.ForeignKey('Author', on_delete=models.CASCADE, null=False, db_column='author_id') # コメントアウトを外しました

    class Meta:
        db_table = 'book'

これで、0003から始まるマイグレーションファイルが作成されるはずです。

⑤マイグレート実施

これで合計3つのマイグレーションファイルの準備ができましたので、
以下のコマンドですべてのマイグレーションを実行します。

python manage.py migrate

無事に、外部キー制約がある状態でテーブルが作成され、レコードも挿入されていればOKです。

参考・その他

以下の記事を参考させていただきました。

また、マイグレーションファイル内で直接SQLスクリプトを実行してデータを挿入する方法もあると思います。個人的には「fixturesディレクトリさえ見れば挿入した(初期)データがわかる」という点からfixturesの方がわかりやすいかなと感じています。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?