Миграция 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 - Миграции, которые добавляют уникальные поля
Они рекомендуют изменить одну миграцию на три отдельные миграции:
- Создать поле, установить значение null, но не уникальное
- Создание уникальных UUID
- Измените поле, которое будет уникальным
Ответ 3
В этом режиме вы настроили, что вам нужны уникальные значения для полей uuid, но со значениями по умолчанию (одинаковые для всех). Поэтому, если у вас есть два объекта "устройства" в базе данных, миграция добавляет к ним "uuid" значение по умолчанию "uuid.uuid4", и когда он пытается установить его на второй, он выходит из строя из-за уникальных ограничений,
Если вы отбросите свой дБ и создадите новые объекты, вероятно, проблем не будет, но это не решение для производства db, очевидно: D.
Лучшим решением является создание миграции данных, которая устанавливает различное значение uuid (генерируемое библиотекой uuid по умолчанию) для каждого существующего объекта в базе данных. Подробнее о миграции данных вы можете прочитать здесь: https://docs.djangoproject.com/en/1.10/topics/migrations/#data-migrations
Затем, когда вы создаете новые объекты, django автоматически генерирует различные uuid. ;)
Для первичных ключей: Django по умолчанию добавляет его в модель.