我有一个现有的模型,看起来类似于以下内容...
class Resource(models.Model):
id = models.AutoField(primary_key=True)
我们已经使用了一段时间,现在在我们的数据库中有约100万个这些Resource
对象的实例(以及相关的ForeignKey / else用法)。
我现在需要跟踪此模型上的另一个ID,我要强制执行的ID是唯一的。
other_id = models.IntegerField(unique=True)
此other_id
信息当前存储在某些外部CSV中,我想(在过程中的某个时刻)将该信息加载到所有现有的Resource
实例中。
添加以上字段后,Django的makemigrations
可以正常工作。但是,当我对现有数据库应用上述迁移时,出现错误,表明我需要提供默认值以用于所有现有Resource
实例。我敢肯定你们中的许多人都看过类似的东西。
克服此限制的最佳方法是什么?我想到的一些方法...
unique=True
要求other_id
值外部加载到所有现有模型中unique=True
并应用迁移other_id
值other_id
时自动引用这些外部CSV来加载manage.py migrate
值。如果(在将来的某个时刻)有人重新运行这些迁移而这部分失败(无法在CSV中找到现有资源id
来提取other_id
),则可能会遇到问题。所有这些感觉都很复杂,但是我想我想做的也不是最简单的事情。
有什么想法吗?我必须想象过去有人不得不解决类似的问题。
谢谢!
答案 0 :(得分:2)
实际上,源或问题本身并不是唯一的约束,而是您的字段不允许为null且没有默认值的事实-对于非唯一字段,您将遇到同样的错误。< / p>
此处的正确解决方案是允许该字段为空(null=True
),并将其默认设置为None
(它将转换为sql“ null”)。由于null
值被排除在唯一约束之外(至少在数据库供应商遵守SQL标准的情况下),因此,这使您可以应用架构更改,同时仍可以确保非空值不能重复。
然后,您可能希望进行数据迁移以加载已知的“ other_id”值,并最终进行第三次架构迁移以不允许该字段为空值-仅当且仅当您知道已为所有记录填充此字段时。
答案 1 :(得分:1)
Django有一个名为Data Migrations的东西,您可以在其中创建一个迁移文件,该文件在应用迁移时会修改/删除/向数据库添加数据。
在这种情况下,您将创建3个不同的迁移:
null=True
使用空值的迁移。null=True
,创建禁止空值的迁移。然后,您运行python manage.py migrate
时,它将以正确的顺序应用步骤1-3中的所有迁移。
您的数据迁移看起来像这样:
from django.db import migrations
def populate_reference(apps, schema_editor):
MyModel = apps.get_model('yourappname', 'MyModel')
for obj in MyModel.objects.all():
obj.other_id = random_id_generator()
obj.save()
class Migration(migrations.Migration):
dependencies = [
('yourappname', '0001_initial'),
]
operations = [
migrations.RunPython(populate_reference),
]
您可以使用./manage.py makemigrations --empty yourappname
命令创建一个空的迁移文件。