Я меняю поле с 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) Теперь примените миграцию.