【问题标题】:UUID field added after data already in database. Is there any way to populate the UUID field for existing data?在数据库中已有数据之后添加的 UUID 字段。有没有办法为现有数据填充 UUID 字段?
【发布时间】:2012-09-10 06:46:02
【问题描述】:

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

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

【问题讨论】:

    标签: python django django-models django-south


    【解决方案1】:

    对于以下示例类:

    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 的生成方式都不同。 uuid.py module in Django-extensions 包含您可以创建的 UUID 类型的完整列表。

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

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

    要解决这个问题,您可以在迁移中 need to create a custom iterator(或将其粘贴在真正有用的地方,并在迁移中引用它)。它看起来像这样:

    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()
    

    【讨论】:

    • 即使反对者看不到这一点;无论如何我都会说:如果你因为我提供了赏金而对我投了反对票,然后回答了这个问题,请注意,无论如何我都无法收回我的赏金,所以我不会回答赏金问题。我正在回答这个问题,因为在我提出赏金之后的一段时间,无论如何我都必须这样做,所以我想我会与大家分享我是如何做到的。
    • 嗨,George,我个人因此投了反对票,但我是新手,不知道你不能拿回自己的赏金。我收回了我的反对票,在查看您的个人资料后,您可以看出您是堆栈中一位忠诚、聪明且有用的成员 :)
    【解决方案2】:

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

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

    引用:

    您需要导入以下 import uuid

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

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

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

    【讨论】:

      【解决方案3】:

      在 Django 文档中,这个确切的问题现在有一个 excellent, updated answer for Django 1.9

      为我节省了很多时间!

      【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-07-16
      • 2018-05-08
      • 2014-03-31
      • 1970-01-01
      相关资源
      最近更新 更多