2016-02-08 32 views
15

Tôi có trường uuid (không phải là khóa chính). Sự di cư được tạo ra là:Di chuyển Django với trường uuid tạo ra các giá trị trùng lặp

from __future__ import unicode_literals 

from django.db import migrations, models 
import uuid 


class Migration(migrations.Migration): 

    dependencies = [ 
     .... 
    ] 

    operations = [ 
     ... 
     migrations.AddField(
      model_name='device', 
      name='uuid', 
      field=models.UUIDField(default=uuid.uuid4, unique=True), 
     ), 
     ... 
    ] 

Nhưng khi làm python manage.py migrate nó được đâm với:

django.db.utils.IntegrityError: could not create unique index "restaurants_device_uuid_key" DETAIL: Key (uuid)=(f3858ded-b8e0-4ac0-8436-8a61b10efc73) is duplicated.

Lạ lùng thay, vấn đề dường như không xảy ra với các phím chính (được có thể được tạo ra bởi các cơ sở dữ liệu, và không phải nội bộ bởi django?)

Làm cách nào để thêm trường uuid và đảm bảo di chuyển hoạt động?

+3

Các tài liệu giải thích điều này khá tốt, xem [Migrations mà thêm trường duy nhất] (https://docs.djangoproject.com/en/1.9/howto/writing-migrations/#migrations-that-add-unique -lĩnh vực). – knbk

+0

@knbk: Cảm ơn. Thật là tuyệt vời. Amaizingly thú vị và đáng kinh ngạc phức tạp. Chỉ .. để .. tạo ra .. uuids – dangonfast

+0

Cách khác, nó là một hack nhưng cho một chức năng tương tự, và cách đơn giản hơn: str_uuid = models.CharField (max_length = 36, default = lambda: str (uuid.uuid4())). Sau khi di chuyển, chạy một vòng lặp cho từng đối tượng trong mô hình và lưu() nó để có được một uuid duy nhất. Bạn không cần một chỉ mục duy nhất vì cơ hội của cùng uuid4 gần bằng không. –

Trả lời

1

Trong chế độ, bạn đã định cấu hình, bạn muốn giá trị duy nhất cho các trường uuid, nhưng có giá trị mặc định (giống nhau cho tất cả). Vì vậy, nếu bạn có hai đối tượng 'thiết bị' trong cơ sở dữ liệu, thì việc di chuyển thêm trường 'uuid' vào chúng với giá trị 'uuid.uuid4' mặc định và khi nó cố đặt giá trị thứ hai, nó bị treo do các ràng buộc duy nhất .

Nếu bạn thả db của mình và tạo đối tượng mới có thể sẽ không có vấn đề nhưng đó không phải là giải pháp cho db sản xuất rõ ràng: D.

Giải pháp tốt hơn là tạo di chuyển dữ liệu đặt giá trị uuid khác nhau (được tạo bởi thư viện 'uuid' mặc định) cho mọi đối tượng hiện có trong cơ sở dữ liệu. Bạn có thể đọc thêm về di chuyển dữ liệu tại đây: https://docs.djangoproject.com/en/1.10/topics/migrations/#data-migrations

Sau đó, khi bạn tạo đối tượng mới, django sẽ tự động tạo ra các uuid khác nhau. ;)

Đối với khóa chính: Django thêm nó vào mô hình theo mặc định.

7

(trả lời lấy từ những nhận xét đầu tiên)

Xem các tài liệu django - Migrations that add unique fields

Họ nên thay mới di cư duy nhất của bạn thành ba di cư riêng biệt:

  1. Tạo lĩnh vực, thiết lập để null nhưng không độc đáo
  2. Tạo UUID duy nhất
  3. Thay đổi trường thành duy nhất
10

Dưới đây là ví dụ làm mọi thứ trong một lần di chuyển đơn lẻ nhờ cuộc gọi RunPython.

# -*- coding: utf-8 -* 
from __future__ import unicode_literals 

from django.db import migrations, models 
import uuid 


def create_uuid(apps, schema_editor): 
    Device = apps.get_model('device_app', 'Device') 
    for device in Device.objects.all(): 
     device.uuid = uuid.uuid4() 
     device.save() 


class Migration(migrations.Migration): 

    dependencies = [ 
     ('device_app', 'XXXX'), 
    ] 

    operations = [ 
     migrations.AddField(
      model_name='device', 
      name='uuid', 
      field=models.UUIDField(blank=True, null=True), 
     ), 
     migrations.RunPython(create_uuid), 
     migrations.AlterField(
      model_name='device', 
      name='uuid', 
      field=models.UUIDField(unique=True) 
     ) 
    ] 
Các vấn đề liên quan