我设法通过创建三个迁移来实现这一点。我从以下模型开始:
class MyModel(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
created_at = models.DateTimeField(auto_now_add=True)
首先,我们需要迁移来重命名主键字段并添加一个新的id
占位符 IntegerField:
class Migration(migrations.Migration):
dependencies = [
('myapp', '0001_initial'),
]
operations = [
migrations.RenameField(
model_name='mymodel',
old_name='id',
new_name='uuid',
),
migrations.AddField(
model_name='mymodel',
name='new_id',
field=models.IntegerField(null=True),
),
]
现在在下一次迁移中,我们需要id
根据我们想要的顺序回填 IntegerField(我将使用created_at
时间戳)。
def backfill_pk(apps, schema_editor):
MyModel = apps.get_model('myapp', 'MyModel')
curr = 1
for m in MyModel.objects.all().order_by('created_at'):
m.new_id = curr
m.save()
curr += 1
class Migration(migrations.Migration):
dependencies = [
('myapp', '0002_rename_pk'),
]
operations = [
migrations.RunPython(backfill_pk, reverse_code=migrations.RunPython.noop),
]
最后我们需要将uuid
andid
字段更改为正确的最终配置(注意下面的操作顺序很重要):
class Migration(migrations.Migration):
dependencies = [
('myapp', '0003_backfill_pk'),
]
operations = [
migrations.AlterField(
model_name='mymodel',
name='uuid',
field=models.UUIDField(db_index=True, default=uuid.uuid4, editable=False, unique=True),
),
migrations.AlterField(
model_name='mymodel',
name='new_id',
field=models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
),
migrations.RenameField(
model_name='mymodel',
old_name='new_id',
new_name='id',
),
]
最终的模型状态将如下所示(该id
字段在 Django 中是隐式的):
class MyModel(models.Model):
uuid = models.UUIDField(default=uuid.uuid4, db_index=True, editable=False, unique=True)
created_at = models.DateTimeField(auto_now_add=True)