Как (вручную?) Удалить и воссоздать ограничения по ключам в миграции django - PullRequest
2 голосов
/ 07 марта 2019

Я думаю, что у меня есть довольно туманный случай, который Джанго не освещает.Я использую Django 1.11.20, и эта проблема возникает при использовании mySQL, с sqlite проблем нет (так как здесь не используются ограничения на использование внешних ключей)

Итак, вот настройки.

  • У меня есть модель с именем 'Function', и у нее есть поле автоматического первичного ключа 'id' (сделано Django)
  • У меня есть модель с именем 'Training' ичто существует отношение ManyToMany, называемое «subscribe_functions», которое указывает на функцию.

    class Training(RegistrationBlock):

    subscribe_functions = models.ManyToManyField('Function', blank=False, limit_choices_to={'avail_option': True},
                                             related_name="trainings",
                                             verbose_name=_('Functiongroups that may register'),
                                             help_text=_('People in the selected functions may register their '
                                                         'availability'))
    

Таким образом, Django создал хорошую промежуточную таблицу для этого и нав этой таблице есть ограничение внешнего ключа, которое столбец 'function_id' указывает на Function.id.

И вот проблема.

Теперь я хочу добавить родителямодель для функции без потери данных и фактически переместить некоторые данные в родительский.Поэтому я делаю родительскую модель ('CoreFunction') и переносу ее (она находится в отдельном приложении), а затем в своей миграции для функции я делаю следующее:

  • переименование поля 'id 'on Function в' corefunction_ptr '

    migrations.RenameField(
        model_name='function',
        old_name='id',
        new_name='corefunction_ptr'
    ),
    
  • Передать некоторые данные из дочерней модели в родительскую модель с помощью операции RunPython

  • и затем сделайте следующее:

    migrations.AlterField(
        model_name='function',
        name='corefunction_ptr',
        field=models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='rlgcore.CoreFunction'),
    ),
    

По существу, превращение поля corefunction_ptr в поле primary_key и указание его на родительскую модель.

При запуске этой миграции на mySQLБаза данных Я получаю сообщение об ошибке, что существует ограничение внешнего ключа и что поле corefunction_ptr не может быть изменено.

_mysql_exceptions.OperationalError: (1846, 'ALGORITHM=COPY is not supported. Reason: Columns participating in a foreign key are renamed. Try ALGORITHM=INPLACE.')

Копая в моей базе данных, я обнаружил, что это ограничение для промежуточной таблицы training_subscribeefunctions .

Я точно определил его в этом запросе (который выдает ту же ошибку при выдаче в phpmyadmin).ALTER TABLE 'pe_function' CHANGE 'corefunction_ptr' 'corefunction_ptr_id' integer NOT NULL;

Однако была другая модель, связанная с Function через ForeignKey, и для этой таблицы ограничение было удалено и позже будет создано заново.(Я запустил python manage.py sqlmigrate [appname] [migrationname], чтобы посмотреть, что происходит)

Я нашел код в Django , где принимается решение о том, следует ли снять ограничение на использование внешней клавиши, но поскольку оно определено длябыть обратным, если многие решения могут привести к ложному ответу.

Таким образом, вопрос заключается в

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

Я нашел способ найти ограничения, указывающие на таблицу через сырой SQLзапрос.Однако я должен был бы хранить всю найденную информацию где-нибудь (глобальные переменные?), Чтобы иметь возможность добавить то же ограничение позже.Я бы предпочел использовать сам код Django (например, из BaseDatabaseSchemaEditor._alter_field ), но я не знаю как.

Я знаю, что функции, которые вы можете передать в RunPython операция получения schema_editor, но я не знаю, как / где получить и как передать параметры _delete_constraint_sql и _create_fk_sql ожидают.

Я бы хотел исправить это с помощью небольшого жесткого кодированияполя / имена таблиц / названия моделей и т. д. насколько возможно.

Есть мысли?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...