使用uuid字段的Django迁移会生成重复值

时间:2016-02-08 23:01:12

标签: python django uuid django-migrations

我有一个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字段,并确保迁移有效?

4 个答案:

答案 0 :(得分:29)

这是一个通过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)
        )
    ]

答案 1 :(得分:16)

(摘自第一条评论)

请参阅django文档 - Migrations that add unique fields

他们建议将单个迁移更改为三个单独的迁移:

  1. 创建字段,设置为null但不是唯一的
  2. 生成唯一的UUID
  3. 将字段更改为唯一

答案 2 :(得分:3)

在模式中,您已配置,您希望uuid字段具有唯一值,但具有默认值(对所有值都相同)。所以,如果你有两个设备'数据库中的对象,迁移添加了uuid'默认' uuid.uuid4'值,当它试图将它设置为第二个时,它会因为唯一约束而崩溃。

如果丢弃数据库并创建新对象可能会出现问题,但这显然不是生产数据库的解决方案:D。

更好的解决方案是创建一个数据迁移,将不同的uuid值(由默认的' uuid'库生成)设置为数据库中的每个现有对象。您可以在此处阅读有关数据迁移的更多信息: https://docs.djangoproject.com/en/1.10/topics/migrations/#data-migrations

然后,当您创建新对象时,django将自动生成不同的uuid。 ;)

对于主键:Django默认将它添加到模型中。

答案 3 :(得分:0)

您可以在模型中创建uu_id列后提供管理命令来填充uuid字段,但这必须在迁移模型并将字段默认设置为“无”之后完成。

from django.core.management.base import BaseCommand
from django.apps import apps
import uuid


class Command(BaseCommand):
    def handle(self, *args, **options):
        classes()


def classes():
    app_models = apps.get_app_config('appname').get_models()
    for model in app_models:
        field = None
        try:
            field = model._meta.get_field('uu_id')
        except:
            pass

        if field:

            uu_id_list = list(model.objects.all().values_list('uu_id',flat=True))
            if None in uu_id_list:
                for row in model.objects.all():
                    row.uu_id = uuid.uuid4()
                    row.save()