17

我在一些模型中添加了一个 UUID 字段,然后使用 South 迁移。我创建的任何新对象都正确填充了 UUID 字段。但是,我所有旧数据的 UUID 字段为空。

有没有办法为现有数据填充 UUID 数据?

4

3 回答 3

19

对于以下示例类:

from django_extensions.db.fields import UUIDField

def MyClass:
    uuid = UUIDField(editable=False, blank=True)
    name = models.CharField()

如果您使用的是 South,请创建数据迁移:

python ./manage.py datamigration <appname> --auto

然后使用以下代码使用特定逻辑更新迁移以添加 UUID:

from django_extensions.utils import uuid

def forwards(self, orm):
    for item in orm['mypp.myclass'].objects.all():
        if not item.uuid:
            item.uuid = uuid.uuid4() #creates a random GUID
            item.save()


def backwards(self, orm):
    for item in orm['mypp.myclass'].objects.all():
        if item.uuid:
            item.uuid = None
            item.save()

您可以创建不同类型的 UUID,每个 UUID 生成方式不同。Django-extensions 中的uuid.py 模块包含您可以创建的 UUID 类型的完整列表。

请务必注意,如果您在包含大量对象的环境中运行此迁移,则可能会超时(例如,如果使用结构进行部署)。生产环境将需要另一种填充现有字段的方法。

尝试对大量对象执行此操作时可能会出现内存不足(我们发现自己内存不足并且部署失败,有 17,000 多个对象)。

为了解决这个问题,您需要在迁移中创建一个自定义迭代器(或将其粘贴在真正有用的地方,并在迁移中引用它)。它看起来像这样:

def queryset_iterator(queryset, chunksize=1000):
    import gc
    pk = 0
    last_pk = queryset.order_by('-pk')[0].pk
    queryset=queryset.order_by('pk')
    if queryset.count() < 1
        return []
    while pk < last_pk:
        for row in queryset.filter(pk__gt=pk)[:chunksize]:
            pk = row.pk
            yield row
        gc.collect()

然后您的迁移将变为如下所示:

class Migration(DataMigration):

    def forwards(self, orm):
        for item in queryset_iterator(orm['myapp.myclass'].objects.all()):
            if not item.uuid:
                item.uuid = uuid.uuid1()
                item.save()

    def backwards(self, orm):
        for item in queryset_iterator(orm['myapp.myclass'].objects.all()):
            if item.uuid:
                item.uuid = None
                item.save()
于 2013-03-01T17:44:44.663 回答
6

要首先将 UUID 值添加到所有现有记录,您需要确保您的模型具有提交的 UUIDblank=True, null=True

然后使用 south 运行 schemamigration 命令,然后打开生成的迁移文件。然后使用以下内容编辑您的迁移文件,如本文所示

引用:

您需要导入以下导入 uuid

在 forwards() 函数的末尾添加以下 def forwards(self, orm):

...
for a in MyModel.objects.all():
    a.uuid = u'' + str(uuid.uuid1().hex)
    a.save()

如前所述,这将遍历现有实例并向其添加 uuid 作为迁移的一部分。

于 2013-03-01T20:10:17.270 回答
2

在 Django 文档中,对于这个确切的问题, Django 1.9现在有一个很好的更新答案。

节省了我很多时间!

于 2015-12-18T00:51:57.687 回答