概要
Djangoにおいて、あるモデルを修正して、python manage.py makemigrations
すると、次のエラーが生じることがある。
% python manage.py makemigrations It is impossible to add a non-nullable field 'profile' to mymodel without specifying a default. This is because the database needs something to populate existing rows. Please select a fix: 1) Provide a one-off default now (will be set on all existing rows with a null value for this column) 2) Quit and manually define a default value in models.py.
このエラーの対処法をまとめる。
結論
次のようなモデルがあるとする。
class MyModel(models.Model): """My model""" first_name = models.CharField(max_length=10, null=True, blank=True) last_name = models.CharField(max_length=10)
既存のフィールドを変更する場合: e.g.,
first_name
のnull=True
とblank=True
を削除する場合。--> 1)を実行する。
新しいフィールドを追加する場合: e.g.,
profile
フィールドを追加する場合。--> 2)を実行する。オプション
null=True
やdefault='hoge'
などを追加したフィールドを追加する。profile = models.CharField(max_length=50, null=True)
新しいフィールドをオプションなしで追加する場合: e.g., オプションなしの
profile
フィールドを追加する場合。--> 上記の2と1を実行する。
前提知識
- Djangoを知っていることです。ここに書かれてあるコードをそのまま移しても再現されません。ですので想定読者は自分で読み替える程度の知識と経験があることです。
1. 既存のフィールドを変更する場合
mymodel.py
"""My model""" from django.db import models class MyModel(models.Model): """My model""" first_name = models.CharField(max_length=10, null=True, blank=True) last_name = models.CharField(max_length=10)
migrations/0004_mymodel.py
- このファイルは
python manage.py makemigrations
で作成されたものです。
# Generated by Django 5.0.4 on 2024-04-30 03:58 from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ ('books', '0003_store'), ] operations = [ migrations.CreateModel( name='MyModel', fields=[ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('first_name', models.CharField(max_length=10, null=True, blank=True)), ('last_name', models.CharField(max_length=10)), ], ), ]
このとき管理者画面からデータを追加しました。first_name
フィールドはnull=True
およびblank=True
ですので、first_name
が空欄のデータを追加することができます。
ここからmodels.CharField(max_length=10)
に変更するとします。
そのままfirst_name = models.CharField(max_length=10)
と変更して、マイグレーションファイルを作成するとエラーが生じます。
class MyModel(models.Model): """My model""" first_name = models.CharField(max_length=10) last_name = models.CharField(max_length=10)
python manage.py makemigrations It is impossible to change a nullable field 'first_name' on mymodel to non-nullable without providing a default. This is because the database needs something to populate existing rows. Please select a fix: 1) Provide a one-off default now (will be set on all existing rows with a null value for this column) 2) Ignore for now. Existing rows that contain NULL values will have to be handled manually, for example with a RunPython or RunSQL operation. 3) Quit and manually define a default value in models.py.
このとき変更したデータベース(MyModel
)に空のフィールドがあるかどうかで対応が変わります。つまりデータベースのレコードに空のフィールドがある場合と、それ以外(データベースにレコードが存在しないかまたは存在しても空のフィールドがない場合)で修正方法が異なります。まずは後者の空のフィールドがない場合の修正方法です。
1.1 空のフィールドがない場合
コマンドで2)
を選択すれば問題ありません。
python manage.py migrate
してもエラーが生じません。これでフィールドの変更の完了です。
1.2 空のフィールドがある場合
コマンドで2)
を選択して、python manage.py migrate
を実行すると、エラーが生じます。
% python manage.py migrate Operations to perform: Apply all migrations: admin, auth, books, contenttypes, sessions Running migrations: Applying books.0005_alter_mymodel_first_name...Traceback (most recent call last): File "/Users/yoheiwatanabe/.pyenv/versions/3.11.3/lib/python3.11/site-packages/django/db/backends/utils.py", line 105, in _execute return self.cursor.execute(sql, params) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/Users/yoheiwatanabe/.pyenv/versions/3.11.3/lib/python3.11/site-packages/django/db/backends/sqlite3/base.py", line 329, in execute return super().execute(query, params) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .... raise dj_exc_value.with_traceback(traceback) from exc_value File "/Users/yoheiwatanabe/.pyenv/versions/3.11.3/lib/python3.11/site-packages/django/db/backends/utils.py", line 105, in _execute return self.cursor.execute(sql, params) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/Users/yoheiwatanabe/.pyenv/versions/3.11.3/lib/python3.11/site-packages/django/db/backends/sqlite3/base.py", line 329, in execute return super().execute(query, params) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ django.db.utils.IntegrityError: NOT NULL constraint failed: new__books_mymodel.first_name
この場合、データベースのすべてのレコードに空であるフィールドを手動で追加するか、次のようにファイルを修正してください。
0005_alter_mymodel_first_name.py
# Generated by Django 5.0.4 on 2024-04-30 08:29 from django.db import migrations, models def provide_default_for_profile(apps, schema_editor): MyModel = apps.get_model('books', 'MyModel') MyModel.objects.filter(first_name=None).update(first_name='default_value') class Migration(migrations.Migration): dependencies = [ ('books', '0004_mymodel'), ] operations = [ migrations.RunPython(provide_default_for_profile), migrations.AlterField( model_name='mymodel', name='first_name', field=models.CharField(max_length=10), ), ]
このように修正するとpython manage.py migrate
を実行してもエラーになりません。
% python manage.py migrate Operations to perform: Apply all migrations: admin, auth, books, contenttypes, sessions Running migrations: Applying books.0005_alter_mymodel_first_name... OK
2. 新しいフィールドを追加する場合
次のようにprofile
フィールドを追加すると、エラーが生じます。
class MyModel(models.Model): """My model""" first_name = models.CharField(max_length=10) last_name = models.CharField(max_length=10) profile = models.CharField(max_length=50)
% python manage.py makemigrations It is impossible to add a non-nullable field 'profile' to mymodel without specifying a default. This is because the database needs something to populate existing rows. Please select a fix: 1) Provide a one-off default now (will be set on all existing rows with a null value for this column) 2) Quit and manually define a default value in models.py.
null=True
を追加すると解決されます。またはdefault='hoge'
でも問題ありません。
class MyModel(models.Model): """My model""" first_name = models.CharField(max_length=10) last_name = models.CharField(max_length=10) profile = models.CharField(max_length=50, null=True)
% python manage.py makemigrations Migrations for 'books': backend/books/migrations/0006_mymodel_profile.py - Add field profile to mymodel % python manage.py migrate Operations to perform: Apply all migrations: admin, auth, books, contenttypes, sessions Running migrations: Applying books.0006_mymodel_profile... OK
APIでの確認。"profile": null
のデータを作成する。
3. 新しいフィールドをオプションなしで追加する場合
追加したフィールドprofile
にはnull=True
となっていますが、それを削除します。
class MyModel(models.Model): """My model""" first_name = models.CharField(max_length=10) last_name = models.CharField(max_length=10) profile = models.CharField(max_length=50)
% python manage.py makemigrations It is impossible to change a nullable field 'profile' on mymodel to non-nullable without providing a default. This is because the database needs something to populate existing rows. Please select a fix: 1) Provide a one-off default now (will be set on all existing rows with a null value for this column) 2) Ignore for now. Existing rows that contain NULL values will have to be handled manually, for example with a RunPython or RunSQL operation. 3) Quit and manually define a default value in models.py. Select an option: 2 Migrations for 'books': backend/books/migrations/0007_alter_mymodel_profile.py - Alter field profile on mymodel % python manage.py migrate Operations to perform: Apply all migrations: admin, auth, books, contenttypes, sessions Running migrations: Applying books.0007_alter_mymodel_profile... OK
APIでの確認。"profile": null
でエラーになる。
マイグレーションエラーの解決策が少しわかった気がします。
僕から以上