Миграция 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". ДЕТАЛЬ: Key (uuid) = (f3858ded-b8e0-4ac0-8436-8a61b10efc73) дублируется.

Как ни странно, проблема не возникает с первичными ключами (которые, возможно, создаются базой данных, а не внутренне django?)

Как добавить поле uuid и убедиться, что миграция работает?

Ответ 1

Вот пример, который делает все за один переход благодаря вызову RunPython.

# -*- 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)
        )
    ]

Ответ 2

(Ответ сделан с первого комментария)

См. Django docs - Миграции, которые добавляют уникальные поля

Они рекомендуют изменить одну миграцию на три отдельные миграции:

  1. Создать поле, установить значение null, но не уникальное
  2. Создание уникальных UUID
  3. Измените поле, которое будет уникальным

Ответ 3

В этом режиме вы настроили, что вам нужны уникальные значения для полей uuid, но со значениями по умолчанию (одинаковые для всех). Поэтому, если у вас есть два объекта "устройства" в базе данных, миграция добавляет к ним "uuid" значение по умолчанию "uuid.uuid4", и когда он пытается установить его на второй, он выходит из строя из-за уникальных ограничений,

Если вы отбросите свой дБ и создадите новые объекты, вероятно, проблем не будет, но это не решение для производства db, очевидно: D.

Лучшим решением является создание миграции данных, которая устанавливает различное значение uuid (генерируемое библиотекой uuid по умолчанию) для каждого существующего объекта в базе данных. Подробнее о миграции данных вы можете прочитать здесь: https://docs.djangoproject.com/en/1.10/topics/migrations/#data-migrations

Затем, когда вы создаете новые объекты, django автоматически генерирует различные uuid. ;)

Для первичных ключей: Django по умолчанию добавляет его в модель.