Джанго юг: изменение типа поля при миграции данных

Я меняю поле с CharField на IntegerField. Имя поля остается неизменным. Вновь созданное поле будет основываться на старом поле. Например, если старое поле было "L", вместо него было бы число "1". Как я могу выполнить это в функции forwards()?

Ответ 1

Правильный способ сделать это - разбить это на три миграции:

  • Первой миграции схемы для добавления нового поля IntegerField.
  • После миграции данных для преобразования данных, происходящих из CharField, в IntegerField
  • И окончательная миграция схемы для удаления уже неиспользуемого CharField.

Четвертый может потребоваться, если вы хотите, чтобы ваш новый добавленный IntegerField имел то же имя, что и для удаления CharField.

Учитывая состояние проекта, в котором IntegerField еще не добавлено в файл модели, вы должны выполнить следующие действия:

  • Добавьте модель IntegerField к вам.
  • Создайте миграцию схемы для приложения, содержащего вашу модель. Возможно, вам понадобится указать значение по умолчанию для вашего недавно добавленного поля, если оно не является нулевым.
  • Создайте перенос данных (используя datamigration) для приложения, содержащего вашу модель. В методе forwards() только что созданного класса datamigration запишите свою логику для преобразования ваших данных. Попытайтесь использовать метод менеджера update вместо того, чтобы, если это возможно, повторить всю строку базы данных. Если вы объявите свою логику преобразования с помощью dict (скажем, {'L': 1, ...}), в это время также легко реализовать backwards(), если операция обратима. Это также хорошее упражнение, чтобы убедиться, что вы не упустили обоюдный случай в forwards() - это помогло мне несколько раз в прошлом.
  • Удалите CharField из вашей модели.
  • Создайте миграцию схемы для приложения, содержащего вашу модель, чтобы DROP теперь неиспользуемый столбец.

Тот факт, что вы нарушили эту операцию в три миграции, вместо того, чтобы записывать всю свою логику в пустой шаблон, имеет несколько преимуществ:

  • Автоматически создаваемые операции DDL: логика ADD/DROP была автоматически сгенерирована Югом, и вам не нужно беспокоиться о вводе опечатки в столбце базы данных.
  • Полностью обратимая операция: учитывая, что вы потратили время на реализацию DataMigration.backwards() для шага преобразования, вы сможете полностью отменить всю операцию. Это может быть полезно для целей тестирования, если вам необходимо откат к предыдущей ревизии вашего кода и как безопасная сеть при обновлении базы производственного кода.
  • Атоматичность операций: тот факт, что каждая операция изолирована и запускается в ней, собственная транзакция не оставит вас в противоречивом состоянии между вашей базой данных и вашей южной миграцией. Например, если все операции выполнялись в одной миграции (в этом случае в том же методе forwards()), и исключение было создано во время этапа переноса данных (скажем, KeyError из-за необработанного значения в вашем преобразовании dict). Если вы используете ORDBMS, который не поддерживает изменение схемы транзакций, вы не сможете повторно выполнить миграцию сразу после исправления части переноса данных, вам придется вручную удалить вновь добавленную IntegerField колонка самостоятельно. Опять же, это то, о чем вы не хотите иметь дело при миграции производственной базы данных.
  • Возможность выполнения сухого запуска: также очень удобно при переносе производственной базы данных.

Ответ 2

для той же ситуации меня выполнили всего 3 шага.

1) изменил тип файла с CharField на IntegerField,

2) ALTER TABLE the_table ALTER COLUMN col_name TYPE integer USING (col_name:: integer); или

ALTER TABLE the_table ALTER COLUMN col_name TYPE integer ИСПОЛЬЗОВАНИЕ (trim (col_name):: integer); #, если у вас есть пробел в поле Char или в текстовом поле. и если у вас есть данные в вашей таблице, которая должна быть целым числом.

3) Теперь примените миграцию.