web-dev-qa-db-ja.com

Django uuidフィールドを使用した移行では、重複した値が生成されます

uuidフィールドがあります(主キーではありません)。生成される移行は次のとおりです。

from __future__ import unicode_literals

from Django.db import migrations, models
import uuid


class Migration(migrations.Migration):

    dependencies = [
        ....
    ]

    operations = [
        ...
        migrations.AddField(
            model_name='device',
            name='uuid',
            field=models.UUIDField(default=uuid.uuid4, unique=True),
        ),
        ...
    ]

しかし、python manage.py migrateそれはクラッシュしています:

Django.db.utils.IntegrityError:一意のインデックス "restaurants_device_uuid_key"を作成できませんでした詳細:キー(uuid)=(f3858ded-b8e0-4ac0-8436-8a61b10efc73)が重複しています。

奇妙なことに、この問題は主キーでは発生しないようです(主キーはデータベースによって作成され、djangoによって内部的に作成されるのではないでしょうか?)

Uuidフィールドを追加して、移行が機能することを確認するにはどうすればよいですか?

35
dangonfast

RunPython呼び出しのおかげで、1回の移行ですべてを実行する例を次に示します。

# -*- coding: utf-8 -*
from __future__ import unicode_literals

from Django.db import migrations, models
import uuid


def create_uuid(apps, schema_editor):
    Device = apps.get_model('device_app', 'Device')
    for device in Device.objects.all():
        device.uuid = uuid.uuid4()
        device.save()


class Migration(migrations.Migration):

    dependencies = [
        ('device_app', 'XXXX'),
    ]

    operations = [
        migrations.AddField(
            model_name='device',
            name='uuid',
            field=models.UUIDField(blank=True, null=True),
        ),
        migrations.RunPython(create_uuid),
        migrations.AlterField(
            model_name='device',
            name='uuid',
            field=models.UUIDField(unique=True)
        )
    ]
34
v.thorey

(最初のコメントからの回答)

Django docs- 一意のフィールドを追加する移行

単一の移行を3つの個別の移行に変更することをお勧めします。

  1. Nullに設定されているが一意ではないフィールドを作成
  2. 一意のUUIDを生成する
  3. フィールドを一意に変更します
20
Alex L

このモードでは、uuidフィールドに一意の値が必要ですが、デフォルト値(すべて同じ)を設定しました。そのため、データベースに2つの「デバイス」オブジェクトがある場合、移行によってデフォルトの「uuid.uuid4」値で「uuid」フィールドが追加され、2番目のオブジェクトに設定しようとすると、一意の制約のためにクラッシュします。

データベースを削除して新しいオブジェクトを作成した場合、おそらく問題はありませんが、実稼働データベースの解決策ではないことは明らかです:D。

より良い解決策は、データベース内のすべての既存オブジェクトに異なるuuid値(デフォルトの「uuid」ライブラリーによって生成される)を設定するデータ移行を作成することです。データの移行の詳細については、こちらをご覧ください。 https://docs.djangoproject.com/en/1.10/topics/migrations/#data-migrations

次に、新しいオブジェクトを作成すると、Djangoは異なるuuidを自動的に生成します。;)

主キーの場合:Djangoはデフォルトでモデルに追加します。

4
Ivo Donchev