python django django-models django-south

python - Campo UUID agregado después de datos ya en la base de datos. ¿Hay alguna manera de rellenar el campo UUID para los datos existentes?



django django-models (3)

He agregado un campo UUID a algunos de mis modelos y luego migré con South. Cualquier nuevo objeto que cree tiene el campo UUID rellenado correctamente. Sin embargo, los campos UUID en todos mis datos anteriores son nulos.

¿Hay alguna manera de llenar los datos UUID para los datos existentes?



Para agregar primero los valores UUID a todos los registros existentes, deberá asegurarse de que su modelo tenga el UUID archivado con blank=True, null=True

Luego ejecute el comando schemamigration con south y luego abra el archivo de migración resultante. Y luego edite su archivo de migración con lo siguiente como se muestra en esta post

Citar:

Tendrá que importar el siguiente uuid de importación

Al final de la función forwards (), agregue la siguiente def forward (self, orm):

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

Como se indicó, recorrerá las instancias existentes y le agregará un uuid como parte de la migración.


Para la siguiente clase de muestra:

from django_extensions.db.fields import UUIDField def MyClass: uuid = UUIDField(editable=False, blank=True) name = models.CharField()

Si está utilizando South, cree una migración de datos:

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

Y luego use el siguiente código para actualizar la migración con la lógica específica para agregar un 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()

Puede crear diferentes tipos de UUID, cada uno generado de manera diferente. El módulo uuid.py en Django-extensions tiene la lista completa de los tipos de UUID que puede crear.

Es importante tener en cuenta que si ejecuta esta migración en un entorno con una gran cantidad de objetos, es posible que se agote el tiempo de espera (por ejemplo, si utiliza la estructura para implementar). Se requerirá un método alternativo para completar los campos ya existentes para los entornos de producción.

Es posible que se quede sin memoria al intentar hacer esto con una gran cantidad de objetos (nos encontramos con que nos estamos quedando sin memoria y el despliegue falla con más de 17,000 objetos).

Para solucionar esto, necesita crear un iterador personalizado en su migración (o mantenerlo donde sea realmente útil y referirse a él en su migración). Se vería algo como esto:

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

Y luego sus migraciones cambiarían para verse así:

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