Поле 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.
сэкономил мне много времени!