数据已经存在于数据库中后添加了UUID字段.有没有办法为现有数据填充UUID字段?

bli*_*uck 17 python django django-models django-south

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

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

Geo*_*ker 19

对于以下示例类:

from django_extensions.db.fields import UUIDField

def MyClass:
    uuid = UUIDField(editable=False, blank=True)
    name = models.CharField()
Run Code Online (Sandbox Code Playgroud)

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

python ./manage.py datamigration <appname> --auto
Run Code Online (Sandbox Code Playgroud)

然后使用以下代码更新迁移,并使用特定逻辑添加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()
Run Code Online (Sandbox Code Playgroud)

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

需要注意的是,如果在具有大量对象的环境中运行此迁移,则可能会超时(例如,如果使用fabric进行部署).生产环境将需要填充现有字段的替代方法.

在尝试对大量对象执行此操作时可能会耗尽内存(我们发现自己内存不足并且部署失败并且有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()
Run Code Online (Sandbox Code Playgroud)

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

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()
Run Code Online (Sandbox Code Playgroud)

  • 尽管挫败者看不到这一点; 无论如何我会说:如果你因为我提供了赏金然后回答了这个问题,那么请你知道我无论如何也不能得到我的赏金,所以我没有回答这个问题.我正在回答这个问题,因为在我提出赏金之后的一段时间,无论如何我都必须这样做,所以我想我会和大家分享我是怎么做到的. (4认同)

Gly*_*son 6

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

然后使用south运行schemamigration命令,然后打开生成的迁移文件.然后编辑用下面的迁移文件,如在这个岗位

引用:

您需要导入以下导入uuid

在forwards()函数结束时添加以下def前进(self,orm):

...
for a in MyModel.objects.all():
    a.uuid = u'' + str(uuid.uuid1().hex)
    a.save()
Run Code Online (Sandbox Code Playgroud)

如上所述,它将遍历现有实例并在迁移过程中向其添加uuid.