Django UUIDField默认值

3

我有一个Django模型,想要添加一个UUIDField:

uuid = models.UUIDField(
    default = uuid.uuid4,
    unique = True,
    editable = False
)

我希望这个uuid是唯一的,但在迁移现有数据库时,我遇到了以下错误:

django.db.utils.IntegrityError: (1062, "Duplicate entry '3ba46cb5f7f340ffa43e348cb789901a' for key 'carbon.uuid'")

如果已经使用了默认的UUID,我该如何提供另一个UUID?

1
按照以下步骤添加唯一字段 https://docs.djangoproject.com/en/3.0/howto/writing-migrations/#migrations-that-add-unique-fields - Jailton Silva
2个回答

6

您有很多问题,这里有3个步骤可以实现您的目标。

  1. 如果您的模型已经有数据,您需要将其定义为 null=True 并删除 default=uuid.uuid4。为什么?因为如果您设置了默认值,它将尝试在运行迁移时向所有模型添加相同的默认地址,因此对于每一行使用相同的uuid,当您运行迁移时,它会给出错误 django.db.utils.IntegrityError: (1062, "Duplicate entry '3ba46cb5f7f340ffa43e348cb789901a' for key 'carbon.uuid'")

  2. 创建一个迁移来更新您模型中现有的行,并将它们赋予一个uuid,如下所示:phython src/manage.py makemigrations app --name set_uuid_mymodel --empty

# Generated by Django A.B on YYYY-MM-DD HH:MM
from django.db import migrations
import uuid

def gen_uuid(apps, schema_editor):
    MyModel = apps.get_model('myapp', 'MyModel')
    for row in MyModel.objects.all():
        row.uuid = uuid.uuid4()
        row.save(update_fields=['uuid'])

class Migration(migrations.Migration):

    dependencies = [
        ('myapp', '0004_add_uuid_field'),
    ]

    operations = [
        # omit reverse_code=... if you don't want the migration to be reversible.
        migrations.RunPython(gen_uuid, reverse_code=migrations.RunPython.noop),
    ]

请查看官方文档:https://docs.djangoproject.com/en/3.0/howto/writing-migrations/#migrations-that-add-unique-fields 然后你可以在模型的save方法中管理新行生成的uuid。
def save(self, *args, **kwargs):
    ''' On save, update uuid and ovoid clash with existing code '''
    if not self.uuid:
        self.uuid = uuid.uuid4()
    return super(YourModel, self).save(*args, **kwargs)

3
为了为模型添加一个新的必填字段 (null=False),你需要包含一个默认值。这个默认值将应用于所有现有的记录。
对于 UUIDField,在迁移期间,Django 不会为每个记录创建一个新的 UUID 值。一个单一的值通过 uuid.uuid4() 生成,并使用单个 SQL 应用于所有记录。因此,如果你在数据库中有现有记录,并且知道 unique=True 是在数据库级别上应用的,那么在迁移期间将出现 IntegrityError 的情况。
如果你需要具有有效 uuid 值的现有记录 (你无法重新创建整个模型迁移与 uuid 字段或者在运行迁移前删除现有的记录),可以使用迁移内的 RunPython operation 强制为每个记录设置新值。
编辑你的迁移以执行以下步骤:
  1. 添加一个可空的 uuid 字段,没有 uniquedefault 设置,以便 Django 可以创建该列而不会出现完整性错误。
  2. 添加自定义 Python 代码以强制现有记录的 uuid
  3. 更改 uuid 字段,恢复原始设置
import uuid

from django.db import migrations


def force_uuid(apps, schema_editor):
    # We get the model from the versioned app registry;
    # if we directly import it, it'll be the wrong version
    MyModel = apps.get_model('myapp', 'MyModel')
    db_alias = schema_editor.connection.alias

    for instance in MyModel.objects.using(db_alias).all():
        instance.uuid = uuid.uuid4()
        instance.save()


class Migration(migrations.Migration):
    dependencies = []
    operations = [
        # Pre generate the uuid field (nullable)
        migrations.AddField(
            model_name='mymodel',
            name='uuid',
            field=models.UUIDField(null=True, unique=False, editable=False),
        ),
        # Force uuid on existing records
        migrations.RunPython(force_uuid),
        # Recovering original settings
        migrations.AlterField(
            model_name='mymodel',
            name='uuid',
            field=models.UUIDField(
                default=uuid.uuid4, null=False, unique=True, editable=False
            ),
        ),
    ]


注意事项

  • 如果您有很多记录需要生成唯一的UUID,可以使用bulk_create()而不是遍历所有记录并添加许多单个插入。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接