Поле UUID добавлено после данных уже в базе данных. Есть ли способ заполнить поле UUID для существующих данных?

Я добавил поле UUID к некоторым из моих моделей, а затем мигрировал с юга. Любые новые объекты, которые я создаю, имеют поле UUID, заполненное правильно. Однако поля UUID для всех моих старых данных имеют значение null.

есть ли способ заполнить данные UUID для существующих данных?

3 ответов


для следующего образца класса:

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, каждый из которых генерируется по-разному. the uuid.py модуль в Django-расширения имеет полный список типов UUIDs, которые вы можете создать.

важно отметить, что если вы выполняете эту миграцию в среде с большим количеством объектов, у нее есть потенциал для тайм-аута (например, при использовании fabric для развертывания). Для производственных сред потребуется альтернативный метод заполнения уже существующих полей.

при попытке сделать это с большим количеством объектов может закончиться память (мы обнаружили, что у нас заканчивается память и происходит сбой развертывания с 17,000+ объектами).

чтобы обойти это, вы необходимо создать пользовательский итератор в вашей миграции (или придерживаться его, где это действительно полезно, и ссылаться на него в миграции). Это выглядело бы примерно так:--6-->

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

чтобы добавить значения UUID ко всем существующим записям, сначала вам нужно будет убедиться, что ваша модель имеет UUID, поданный с blank=True, null=True

затем запустите команду schemamigration с south, а затем откройте полученный файл миграции. А затем отредактируйте файл миграции следующим образом, как показано в этом в должности

цитата:

вам нужно импортировать следующий UUID импорта

в конце функции forwards() добавить следующий def вперед (self, orm):

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

как указано, что будет цикл через существующие экземпляры и добавить uuid к нему как часть миграции.


сейчас отличный, обновленный ответ для Django 1.9 к этому точному вопросу в документах Django.

сэкономил мне много времени!