Как изменить поле ПК на существующей модели? - PullRequest
0 голосов
/ 05 ноября 2019

У меня есть пользовательская модель, в которой в качестве поля pk используется AutoField. Теперь я хочу изменить pk на uuid, так как мне нужно использовать его в моем API. Самая большая проблема заключается в том, что проект уже запущен, и есть некоторые сторонние приложения, которые имеют отношение к модели пользователя. Например, это модель маркера DRF.

Я попытался написать несколько миграций для замены таблиц и обеспечения безопасности моих данных.

вот модель пользователя:

class User(PermissionsMixin, AbstractBaseUser): 

    email = models.EmailField(_("email address"), max_length=64, unique=True)
    first_name = models.CharField(_("first name"), max_length=30, blank=True)
    last_name = models.CharField(_("last name"), max_length=50, blank=True)

Вотмои шаги:

1) Я создал первую миграцию, добавив uuid = models.UUIDField(default=uuid4, editable=False)

2) Затем я создал пустые миграции и заполнил новые uuids

from uuid import uuid4

from django.db import migrations


def fill_ids(apps, schema_editor):
    user_model = apps.get_model("users", "User")
    for user in user_model.objects.all():
        user.uuid = uuid4()
        user.save()

class Migration(migrations.Migration):
    dependencies = [
        ('users', '0002_user_uuid'),
    ]

    operations = [
        migrations.RunPython(fill_ids)
    ]

3) ПередНа этом этапе все работает хорошо. Затем я попытался заполнить соответствующие модели новыми идентификаторами

from django.db import migrations, models
from django.conf import settings


def change_model_fks(apps, schema_editor):
    log_model = apps.get_model('admin', 'logentry')
    token_model = apps.get_model('authtoken', 'token')  
    user_model = apps.get_model('users', "user")  

    mapping = {}
    for user in user_model.objects.all():
        mapping[user.id] = user.uuid  # map old primary keys to new
    for token in token_model.objects.all():
        if token.user_id:
            token.user_id = mapping[token.user_id]
            token.save()
    for log in log_model.objects.all():
        if log.user_id:
            log.user_id = mapping[log.user_id]
            log.save()


class Migration(migrations.Migration):

    dependencies = [
        ('users', '0003_auto_20191105_1601'),
        ('authtoken', '0002_auto_20160226_1747'),
        ('admin', '0003_logentry_add_action_flag_choices')
    ]

    operations = [
        migrations.AlterField(
         model_name="Token",
         name='user',
         field=models.ForeignKey(to=settings.AUTH_USER_MODEL, on_delete=models.CASCADE, verbose_name='user',
                                 db_constraint=False)
        ),
        migrations.AlterField(
            model_name="EntryLog",
            name='user',
            field=models.OneToOneField(to=settings.AUTH_USER_MODEL, related_name='auth_token',
                                       on_delete=models.CASCADE, db_constraint=False)
        ),
        migrations.RunPython(change_model_fks, atomic=True),
        migrations.AlterField(
            model_name="Token",
            name='user',
            field=models.ForeignKey(to=settings.AUTH_USER_MODEL, on_delete=models.CASCADE, verbose_name='user')
        ),
        migrations.AlterField(
            model_name="EntryLog",
            name='user',
            field=models.OneToOneField(to=settings.AUTH_USER_MODEL, related_name='auth_token', on_delete=models.CASCADE)
        ),
    ]

. Я перенес эти миграции с ошибкой: KeyError: ('users', 'token')

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

Как правильно выполнить миграцию, чтобы распознавать модели из других модулей?

...