【问题标题】:How to make UUID field default when there's already ID field当已有 ID 字段时如何使 UUID 字段默认
【发布时间】:2018-06-20 08:49:00
【问题描述】:

我正在做一个项目,问题是我已经创建了带有简单 ID 列的模型,但现在我的要求发生了变化,我想用 UUID 字段替换 ID 字段(模型),我刚刚更新了我的模型:

uuid = models.UUIDField(primary_key=True, default=uuid.uuid4)

但是当我运行迁移时出现错误

django.db.utils.OperationalError: (1829, "Cannot drop column 'id': 在外键约束中需要

请指导我如何执行此迁移?

【问题讨论】:

  • 你在哪里用过这个模型作为对外关系?
  • 是的,我用过
  • 那你先删除它,makemigrations,然后用uuid migrate改变这个模型,然后在另一个模型中使用它,然后再次迁移
  • 你能分享一些代码sn-p吗?对我来说会很方便!
  • 这个没有代码,只是按照我之前说的步骤来的

标签: django python-3.x django-models django-rest-framework


【解决方案1】:

这里是您需要执行的操作列表

1 - 将新的uuid 字段添加到模型(我将此模型命名为Base)然后生成迁移文件

uuid = models.UUIDField(default=uuid4, blank=True, null=True)

  • 请注意,uuid 还不是主键
  • 注意blank = null =True

2- 在此步骤中,您应该使用有效数据填充 uuid 字段。您应该为Base 模型编写一个数据迁移文件。请查看docs了解更多信息

你的转发方法应该是这样的:

for item in Base.objects.all():
    item.uuid = uuid4()
    item.save()

3- 将 uuid 字段更改为此并生成迁移

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

  • 请注意,uuid 还不是主键,但它现在是唯一的

4 - 对于指向 Base 模型的其他模型,您应该添加一个指向 uuid 字段的新外键

假设您与 Base 模型的默认关系是这样的

base = models.ForeignKey(
    Base, on_delete=models.PROTECT, related_name='base'
)

你应该像这样添加一个临时字段

base_uuid = models.ForeignKey(
    Base,
    on_delete=models.PROTECT,
    related_name='base_uuid',
    to_field='uuid',
    blank=True,
    null=True,
)
  • 注意我已经明确定义了to_field,它告诉django这个外键没有指向默认的pk字段
  • 你应该保留旧的外键字段
  • 还设置blank = null = True
  • 对于所有指向 Base 的外键/manytomanyfield,您应该添加此临时字段

5- 在这一步你应该创建一个数据迁移文件,

在此数据迁移文件中,您需要使用有效数据填充所有base_uuid 字段(基于旧的base 字段)您的迁移代码可以是这样的

for item in RelatedModel.objects.all():
    item.base_uuid_id = item.base.uuid
  • 在此步骤之后,所有模型中的所有 base_uuid 字段都应包含有效数据

6-在所有相关模型中删除相关字段(保留新的base_uuid字段但丢弃旧的相关字段)并生成迁移文件

7- 删除所有 FK 字段上的 db_constraint - 这是必需的,因为 django 将通过来自 base_uuid 的唯一约束进行连接,如果我们将 uuid 更改为 pk,它将被删除。

base_uuid = models.ForeignKey(
    Base,
    on_delete=models.PROTECT,
    related_name='base_uuid',
    to_field='uuid',
    blank=True,
    null=True,
    db_constraint=False
)

8-在Base模型更改uuid字段并生成迁移文件

uuid = models.UUIDField(default=uuid4, primary_key=True)

  • uuid 现在是主键!

9- 在所有相关模型(您已添加base_uuid 字段的模型)中更新字段

  • 重命名字段名(从列名中删除 _uuid)(将此作为单独迁移!)
  • 更改 relate_name 字段名称(从相关名称中删除 _uuid
  • 如有必要,删除blank = null = true
  • 删除 to_field='uuid' 参数(你不再需要那个)

非常重要的注意事项:使用测试数据运行这些代码并从您的数据库创建完整备份,然后再对您的实际数据运行此代码

【讨论】:

  • 很好的答案@aliva,但是,我在第 7 步有一个错误:django.db.utils.ProgrammingError: cannot cast type uuid to integer。我确信我正确地完成了所有步骤。我错过了什么?你知道怎么解决吗?谢谢。
猜你喜欢
  • 2018-06-29
  • 2014-11-09
  • 2015-07-19
  • 2013-03-17
  • 2021-10-13
  • 2018-07-31
  • 2010-10-22
  • 1970-01-01
相关资源
最近更新 更多