0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

DjangoのmodelでUUIDでuniqueなフィールドを追加した手順

Posted at

素人の備忘録です。

参考にしたページ

公式ドキュメント「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ファイルを編集して以下が順に処理されるようにする:

  1. uniqueを外してnull=TrueでAddFieldする。
  2. nullで追加された既存データに対して、それぞれのデータにuuidを生成しつつupdateして埋める。
  3. 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したらうまくいきました。やったー。

0
0
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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?