素人の備忘録です。
参考にしたページ
公式ドキュメント「Migrations that add unique fields」
何も考えずにしたら重複するって怒られた。
uuid_key = models.UUIDField(
default=uuid.uuid4,
unique=True,
editable=False
)
既存のモデルにこれを追加して python manage.py makemigrations
してpython manage.py migrate
したら値が重複するから駄目と怒られました。
DBみたら追加したフィールドに同じUUIDの値をいれようと処理してたみたい。
こうしたら行けた
公式ドキュメントを参考にしつつ、denzowさんのサイトのように1ファイル記述してみた。
概要としては、makemigrationsして出来たmigrationファイルを編集して以下が順に処理されるようにする:
- uniqueを外してnull=TrueでAddFieldする。
- nullで追加された既存データに対して、それぞれのデータにuuidを生成しつつupdateして埋める。
- null=Trueをunique=TrueにAlterFieldする。
準備
- models.pyに上記のuuid_keyの記述を追加する。
- とりあえず
python manage.py makemigrations
する。
出来上がったmigrationファイルを編集する。
最初の状況
0011_add_uuid_field.py
# Generated by Django 4.1.7 on 2023-04-13 01:37
from django.db import migrations, models
import uuid
class Migration(migrations.Migration):
dependencies = [
('myapp', '0010_hitotsumaeno_file'),
]
operations = [
migrations.AddField(
model_name='contentsinfo',
name='uuid_key',
field=models.UUIDField(
default=uuid.uuid4,
editable=False,
null=True), # unique=Trueをnull=Trueに変更。
),
]
まずは field 指定部分のuniqueをnullに変える。
+ field=models.UUIDField(default=uuid.uuid4, editable=False, null=True),
- field=models.UUIDField(default=uuid.uuid4, editable=False, unique=True),
公式サイトを参考にUUID生成する記述を追加。
0011_add_uuid_field.py
# Generated by Django 4.1.7 on 2023-04-13 01:37
from django.db import migrations, models
import uuid
+ def gen_uuid(apps, schema_editor):
+ MyModel = apps.get_model('myapp', 'ContentsInfo') #ここはmodels.pyのクラス名。
+ for row in MyModel.objects.all():
+ row.uuid_key = uuid.uuid4() #ここでrow.<field_name>にするのを忘れずに。
+ row.save(update_fields=['uuid_key']) #ここでも<field_name>を指定。
class Migration(migrations.Migration):
dependencies = [
('myapp', '0010_hitotsumaeno_file'),
]
operations = [
migrations.AddField(
model_name='contentsinfo',
name='uuid_key',
field=models.UUIDField(default=uuid.uuid4, editable=False, null=True),
),
+ #nullなフィールドに都度UUID生成してupdate処理。
+ migrations.RunPython(gen_uuid, reverse_code=migrations.RunPython.noop),
]
最後にnull=True
だった箇所をunique=True
に変更してAlterFieldする指示を書く。
0011_add_uuid_field.py
# Generated by Django 4.1.7 on 2023-04-13 01:37
from django.db import migrations, models
import uuid
def gen_uuid(apps, schema_editor):
MyModel = apps.get_model('myapp', 'ContentsInfo') #ここはmodels.pyのクラス名。
for row in MyModel.objects.all():
row.uuid_key = uuid.uuid4() #ここでrow.<field_name>にするのを忘れずに。
row.save(update_fields=['uuid_key']) #ここでも<field_name>を指定。
class Migration(migrations.Migration):
dependencies = [
('myapp', '0010_hitotsumaeno_file'),
]
operations = [
migrations.AddField(
model_name='contentsinfo',
name='uuid_key',
field=models.UUIDField(
default=uuid.uuid4,
editable=False,
null=True), # unique=Trueをnull=Trueに変更。
),
#nullなフィールドに都度UUID生成してupdate処理。
migrations.RunPython(gen_uuid, reverse_code=migrations.RunPython.noop),
+ # 最初のAddFieldからコピペしてコメント部分を修正する。
+ migrations.AlterField( # AddFieldをAlterFieldにする。
+ model_name='contentsinfo',
+ name='uuid_key',
+ field=models.UUIDField(
+ default=uuid.uuid4,
+ editable=False,
+ unique=True), # null=Trueをunique=Trueに変更。
+ ),
]
できあがったら保存。
できたマイグレーションファイル
0011_add_uuid_field.py
# Generated by Django 4.1.7 on 2023-04-13 01:37
from django.db import migrations, models
import uuid
def gen_uuid(apps, schema_editor):
MyModel = apps.get_model('myapp', 'ContentsInfo') #ここはmodels.pyのクラス名。
for row in MyModel.objects.all():
row.uuid_key = uuid.uuid4() #ここでrow.<field_name>にするのを忘れずに。
row.save(update_fields=['uuid_key']) #ここでも<field_name>を指定。
class Migration(migrations.Migration):
dependencies = [
('myapp', '0010_hitotsumaeno_file'),
]
operations = [
migrations.AddField(
model_name='contentsinfo',
name='uuid_key',
field=models.UUIDField(
default=uuid.uuid4,
editable=False,
null=True), # unique=Trueをnull=Trueに変更。
),
#nullなフィールドに都度UUID生成してupdate処理。
migrations.RunPython(gen_uuid, reverse_code=migrations.RunPython.noop),
# 最初のAddFieldからコピペしてコメント部分を修正する。
migrations.AlterField( # AddFieldをAlterFieldにする。
model_name='contentsinfo',
name='uuid_key',
field=models.UUIDField(
default=uuid.uuid4,
editable=False,
unique=True), # null=Trueをunique=Trueに変更。
),
]
実行してみる。
python manage.py migrate
したらうまくいきました。やったー。