17

一部のモデルにUUIDフィールドを追加してから、Southに移行しました。私が作成する新しいオブジェクトには、UUIDフィールドが正しく入力されています。ただし、古いデータすべてのUUIDフィールドはnullです。

既存のデータのUUIDデータを入力する方法はありますか?

4

3 に答える 3

19

次のサンプルクラスの場合:

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を作成でき、それぞれが異なる方法で生成されます。Django-extensionsのuuid.pyモジュールには、作成できるUUIDのタイプの完全なリストがあります。

オブジェクトが多数ある環境でこの移行を実行すると、タイムアウトになる可能性があることに注意することが重要です(たとえば、ファブリックを使用してデプロイする場合)。実稼働環境では、既存のフィールドに入力する別の方法が必要になります。

多数のオブジェクトに対してこれを実行しようとすると、メモリが不足する可能性があります(メモリが不足し、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()

そして、移行は次のように変更されます。

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()
于 2013-03-01T17:44:44.663 に答える
6

最初に既存のすべてのレコードにUUID値を追加するには、モデルにUUIDがファイルされていることを確認する必要がありますblank=True, null=True

次に、schemamigrationコマンドをsouthで実行し、結果の移行ファイルを開きます。次に、この投稿に示すように、次のように移行ファイルを編集します

引用:

次のインポートuuidをインポートする必要があります

forwards()関数の最後に、次のdef forwards(self、orm)を追加します。

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

前述のように、既存のインスタンスをループし、移行の一部としてuuidを追加します。

于 2013-03-01T20:10:17.270 に答える
2

Djangoのドキュメントには、この正確な質問に対するDjango1.9の優れた更新された回答があります。

たくさんの時間を節約できました!

于 2015-12-18T00:51:57.687 に答える